-module(mochi@response). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/mochi/response.gleam"). -export([success/1, failure/1, partial/2, deferred_patch_to_dynamic/1, incremental_envelope_to_dynamic/2, with_extensions/2, with_extension/3, with_tracing/3, to_dynamic/1, serialize/1, to_json/1, to_json_pretty/1, execution_error_to_graphql_error/1, from_execution_result/1, from_execution_result_incremental/1, has_errors/1, has_data/1, error_count/1, is_success/1, is_partial/1, format/1]). -export_type([incremental_response/0, deferred_patch_response/0, graph_q_l_response/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. -type incremental_response() :: {incremental_response, graph_q_l_response(), list(deferred_patch_response())}. -type deferred_patch_response() :: {deferred_patch_response, list(binary()), gleam@option:option(gleam@dynamic:dynamic_()), gleam@option:option(list(mochi@error:graph_q_l_error())), gleam@option:option(binary()), boolean()}. -type graph_q_l_response() :: {graph_q_l_response, gleam@option:option(gleam@dynamic:dynamic_()), gleam@option:option(list(mochi@error:graph_q_l_error())), gleam@option:option(gleam@dict:dict(binary(), gleam@dynamic:dynamic_())), gleam@option:option(boolean())}. -file("src/mochi/response.gleam", 61). ?DOC(" Create a successful response with data\n"). -spec success(gleam@dynamic:dynamic_()) -> graph_q_l_response(). success(Data) -> {graph_q_l_response, {some, Data}, none, none, none}. -file("src/mochi/response.gleam", 71). ?DOC(" Create an error-only response\n"). -spec failure(list(mochi@error:graph_q_l_error())) -> graph_q_l_response(). failure(Errors) -> {graph_q_l_response, none, {some, Errors}, none, none}. -file("src/mochi/response.gleam", 81). ?DOC(" Create a partial response with data and errors\n"). -spec partial(gleam@dynamic:dynamic_(), list(mochi@error:graph_q_l_error())) -> graph_q_l_response(). partial(Data, Errors) -> {graph_q_l_response, {some, Data}, {some, Errors}, none, none}. -file("src/mochi/response.gleam", 131). ?DOC(" Serialize an incremental response patch to Dynamic\n"). -spec deferred_patch_to_dynamic(deferred_patch_response()) -> gleam@dynamic:dynamic_(). deferred_patch_to_dynamic(Patch) -> Parts = [{<<"path"/utf8>>, gleam_stdlib:identity(erlang:element(2, Patch))}, {<<"data"/utf8>>, case erlang:element(3, Patch) of {some, D} -> D; none -> gleam_stdlib:identity(nil) end}], Parts@1 = case erlang:element(4, Patch) of {some, Errors} -> [{<<"errors"/utf8>>, mochi@error:errors_to_dynamic(Errors)} | Parts]; none -> Parts end, Parts@2 = case erlang:element(5, Patch) of {some, Label} -> [{<<"label"/utf8>>, gleam_stdlib:identity(Label)} | Parts@1]; none -> Parts@1 end, gleam_stdlib:identity(maps:from_list(Parts@2)). -file("src/mochi/response.gleam", 152). ?DOC( " Serialize an incremental delivery envelope to Dynamic\n" " Shape: {\"incremental\": [...patches], \"hasNext\": bool}\n" ). -spec incremental_envelope_to_dynamic( list(deferred_patch_response()), boolean() ) -> gleam@dynamic:dynamic_(). incremental_envelope_to_dynamic(Patches, Has_next) -> gleam_stdlib:identity( maps:from_list( [{<<"incremental"/utf8>>, gleam_stdlib:identity( gleam@list:map(Patches, fun deferred_patch_to_dynamic/1) )}, {<<"hasNext"/utf8>>, gleam_stdlib:identity(Has_next)}] ) ). -file("src/mochi/response.gleam", 168). ?DOC(" Add extensions to a response\n"). -spec with_extensions( graph_q_l_response(), gleam@dict:dict(binary(), gleam@dynamic:dynamic_()) ) -> graph_q_l_response(). with_extensions(Response, Extensions) -> {graph_q_l_response, erlang:element(2, Response), erlang:element(3, Response), {some, Extensions}, erlang:element(5, Response)}. -file("src/mochi/response.gleam", 176). ?DOC(" Add a single extension value\n"). -spec with_extension(graph_q_l_response(), binary(), gleam@dynamic:dynamic_()) -> graph_q_l_response(). with_extension(Response, Key, Value) -> Extensions = case erlang:element(4, Response) of {some, Ext} -> gleam@dict:insert(Ext, Key, Value); none -> maps:from_list([{Key, Value}]) end, {graph_q_l_response, erlang:element(2, Response), erlang:element(3, Response), {some, Extensions}, erlang:element(5, Response)}. -file("src/mochi/response.gleam", 189). ?DOC(" Add tracing data to response extensions\n"). -spec with_tracing(graph_q_l_response(), integer(), integer()) -> graph_q_l_response(). with_tracing(Response, Start_time, End_time) -> Tracing = gleam_stdlib:identity( maps:from_list( [{<<"version"/utf8>>, gleam_stdlib:identity(1)}, {<<"startTime"/utf8>>, gleam_stdlib:identity(Start_time)}, {<<"endTime"/utf8>>, gleam_stdlib:identity(End_time)}, {<<"duration"/utf8>>, gleam_stdlib:identity(End_time - Start_time)}] ) ), with_extension(Response, <<"tracing"/utf8>>, Tracing). -file("src/mochi/response.gleam", 211). ?DOC(" Convert a GraphQLResponse to a Dynamic representation for JSON serialization\n"). -spec to_dynamic(graph_q_l_response()) -> gleam@dynamic:dynamic_(). to_dynamic(Response) -> Parts = [], Parts@1 = [{<<"data"/utf8>>, case erlang:element(2, Response) of {some, D} -> D; none -> gleam_stdlib:identity(nil) end} | Parts], Parts@2 = case erlang:element(3, Response) of {some, Errors} -> [{<<"errors"/utf8>>, mochi@error:errors_to_dynamic(Errors)} | Parts@1]; none -> Parts@1 end, Parts@3 = case erlang:element(4, Response) of {some, Ext} -> [{<<"extensions"/utf8>>, gleam_stdlib:identity(Ext)} | Parts@2]; none -> Parts@2 end, Parts@4 = case erlang:element(5, Response) of {some, V} -> [{<<"hasNext"/utf8>>, gleam_stdlib:identity(V)} | Parts@3]; none -> Parts@3 end, gleam_stdlib:identity(maps:from_list(Parts@4)). -file("src/mochi/response.gleam", 246). ?DOC( " Serialize response to JSON string (requires external JSON encoder)\n" " This returns the Dynamic representation - use with a JSON library\n" ). -spec serialize(graph_q_l_response()) -> gleam@dynamic:dynamic_(). serialize(Response) -> to_dynamic(Response). -file("src/mochi/response.gleam", 272). -spec encode_error_fallback(mochi@output:encode_error(), boolean()) -> binary(). encode_error_fallback(Err, Pretty) -> Message = <<"Internal: "/utf8, (mochi@json:describe_error(Err))/binary>>, Fallback = begin _pipe@1 = failure( [begin _pipe = mochi@error:new(Message), mochi@error:with_code( _pipe, <<"INTERNAL_SERVER_ERROR"/utf8>> ) end] ), to_dynamic(_pipe@1) end, Encoded = case Pretty of true -> mochi@json:encode_pretty(Fallback, 2); false -> mochi@json:encode(Fallback) end, case Encoded of {ok, S} -> S; {error, _} -> <<"{\"data\":null,\"errors\":[{\"message\":\"Internal: response encoding failed\"}]}"/utf8>> end. -file("src/mochi/response.gleam", 256). ?DOC( " Convert a GraphQLResponse to a JSON string.\n" "\n" " If the response data contains a runtime shape that can't be encoded as\n" " JSON (e.g. a resolver returned a tuple or function), fall back to a\n" " spec-compliant error response describing the failure rather than\n" " silently emitting `null` for the offending value.\n" ). -spec to_json(graph_q_l_response()) -> binary(). to_json(Response) -> case mochi@json:encode(to_dynamic(Response)) of {ok, S} -> S; {error, Err} -> encode_error_fallback(Err, false) end. -file("src/mochi/response.gleam", 265). ?DOC( " Convert a GraphQLResponse to a pretty-printed JSON string. Same fallback\n" " behaviour as [`to_json`](#to_json) on encoding failure.\n" ). -spec to_json_pretty(graph_q_l_response()) -> binary(). to_json_pretty(Response) -> case mochi@json:encode_pretty(to_dynamic(Response), 2) of {ok, S} -> S; {error, Err} -> encode_error_fallback(Err, true) end. -file("src/mochi/response.gleam", 297). ?DOC( " Convert an ExecutionError to a GraphQLError\n" " Add source location to a GraphQLError if one is present\n" ). -spec maybe_with_location( mochi@error:graph_q_l_error(), gleam@option:option({integer(), integer()}) ) -> mochi@error:graph_q_l_error(). maybe_with_location(Err, Location) -> case Location of none -> Err; {some, {Line, Col}} -> mochi@error:with_locations(Err, [{location, Line, Col}]) end. -file("src/mochi/response.gleam", 315). -spec execution_error_to_graphql_error(mochi@executor:execution_error()) -> mochi@error:graph_q_l_error(). execution_error_to_graphql_error(Err) -> case Err of {validation_error, Message, Path, Location} -> _pipe = mochi@error:new_at(Message, Path), _pipe@1 = mochi@error:with_category( _pipe, validation_error_category ), maybe_with_location(_pipe@1, Location); {resolver_error, Message@1, Path@1, Location@1} -> _pipe@2 = mochi@error:new_at(Message@1, Path@1), _pipe@3 = mochi@error:with_category( _pipe@2, resolver_error_category ), maybe_with_location(_pipe@3, Location@1); {type_error, Message@2, Path@2, Location@2} -> _pipe@4 = mochi@error:new_at(Message@2, Path@2), _pipe@5 = mochi@error:with_category(_pipe@4, type_error_category), maybe_with_location(_pipe@5, Location@2); {null_value_error, Message@3, Path@3, Location@3} -> _pipe@6 = mochi@error:new_at(Message@3, Path@3), _pipe@7 = mochi@error:with_code( _pipe@6, <<"NULL_VALUE_ERROR"/utf8>> ), _pipe@8 = mochi@error:with_category( _pipe@7, resolver_error_category ), maybe_with_location(_pipe@8, Location@3); {rich_resolver_error, Gql_err, Err_path, Location@4} -> _pipe@9 = {graph_q_l_error, erlang:element(2, Gql_err), erlang:element(3, Gql_err), {some, gleam@list:map( Err_path, fun(Field@0) -> {field_segment, Field@0} end )}, erlang:element(5, Gql_err)}, maybe_with_location(_pipe@9, Location@4) end. -file("src/mochi/response.gleam", 308). -spec map_errors(list(mochi@executor:execution_error())) -> gleam@option:option(list(mochi@error:graph_q_l_error())). map_errors(Errors) -> case Errors of [] -> none; Errs -> {some, gleam@list:map(Errs, fun execution_error_to_graphql_error/1)} end. -file("src/mochi/response.gleam", 91). ?DOC(" Create a response from an ExecutionResult\n"). -spec from_execution_result(mochi@executor:execution_result()) -> graph_q_l_response(). from_execution_result(Result) -> {graph_q_l_response, erlang:element(2, Result), map_errors(erlang:element(3, Result)), none, none}. -file("src/mochi/response.gleam", 101). ?DOC(" Build an incremental response from an ExecutionResult that contains deferred patches\n"). -spec from_execution_result_incremental(mochi@executor:execution_result()) -> incremental_response(). from_execution_result_incremental(Result) -> Has_deferred = not gleam@list:is_empty(erlang:element(4, Result)), Last_idx = erlang:length(erlang:element(4, Result)) - 1, Initial = {graph_q_l_response, erlang:element(2, Result), map_errors(erlang:element(3, Result)), none, case Has_deferred of true -> {some, true}; false -> none end}, Patches = begin _pipe = erlang:element(4, Result), gleam@list:index_map( _pipe, fun(Patch, Idx) -> {deferred_patch_response, erlang:element(2, Patch), erlang:element(3, Patch), map_errors(erlang:element(4, Patch)), erlang:element(5, Patch), Idx < Last_idx} end ) end, {incremental_response, Initial, Patches}. -file("src/mochi/response.gleam", 353). ?DOC(" Check if response has errors\n"). -spec has_errors(graph_q_l_response()) -> boolean(). has_errors(Response) -> case erlang:element(3, Response) of {some, Errors} -> Errors /= []; none -> false end. -file("src/mochi/response.gleam", 361). ?DOC(" Check if response has data\n"). -spec has_data(graph_q_l_response()) -> boolean(). has_data(Response) -> case erlang:element(2, Response) of {some, _} -> true; none -> false end. -file("src/mochi/response.gleam", 369). ?DOC(" Get error count\n"). -spec error_count(graph_q_l_response()) -> integer(). error_count(Response) -> case erlang:element(3, Response) of {some, Errors} -> erlang:length(Errors); none -> 0 end. -file("src/mochi/response.gleam", 377). ?DOC(" Check if response is successful (has data, no errors)\n"). -spec is_success(graph_q_l_response()) -> boolean(). is_success(Response) -> has_data(Response) andalso not has_errors(Response). -file("src/mochi/response.gleam", 382). ?DOC(" Check if response is partial (has data and errors)\n"). -spec is_partial(graph_q_l_response()) -> boolean(). is_partial(Response) -> has_data(Response) andalso has_errors(Response). -file("src/mochi/response.gleam", 391). ?DOC(" Format response for debugging/logging\n"). -spec format(graph_q_l_response()) -> binary(). format(Response) -> Data_str = case erlang:element(2, Response) of {some, _} -> <<"data: "/utf8>>; none -> <<"data: null"/utf8>> end, Errors_str = case erlang:element(3, Response) of {some, Errors} -> Count = erlang:length(Errors), case Count of 1 -> <<"errors: [1 error]"/utf8>>; N -> <<<<"errors: ["/utf8, (erlang:integer_to_binary(N))/binary>>/binary, " errors]"/utf8>> end; none -> <<"errors: none"/utf8>> end, Ext_str = case erlang:element(4, Response) of {some, _} -> <<"extensions: "/utf8>>; none -> <<"extensions: none"/utf8>> end, <<<<<<<<<<<<"GraphQLResponse { "/utf8, Data_str/binary>>/binary, ", "/utf8>>/binary, Errors_str/binary>>/binary, ", "/utf8>>/binary, Ext_str/binary>>/binary, " }"/utf8>>.