runner.ex (2733B)
1 defmodule Absinthe.Plug.Batch.Runner do 2 @moduledoc false 3 4 alias Absinthe.Plug.Request 5 6 def run(queries, conn, conn_info, config) do 7 queries = build_pipelines(queries, conn_info, config) 8 9 queries = prepare(queries) 10 11 {valid_queries, invalid_queries} = 12 Enum.split_with(queries, fn 13 {:ok, _, _, _} -> true 14 {:error, _, _, _} -> false 15 end) 16 17 valid_results = build_valid_results(valid_queries, config.schema_mod) 18 invalid_results = build_invalid_results(invalid_queries) 19 20 bps = restore_order(valid_results, invalid_results) 21 conn = Absinthe.Plug.apply_before_send(conn, bps, config) 22 results = for bp <- bps, do: bp.result 23 {conn, results} 24 end 25 26 defp restore_order(valid_results, invalid_results) do 27 (valid_results ++ invalid_results) 28 |> Enum.sort_by(fn {i, _q} -> i end) 29 |> Enum.map(fn {_i, q} -> q end) 30 end 31 32 defp build_valid_results(valid_queries, schema) do 33 blueprints = 34 Enum.map(valid_queries, fn 35 {:ok, bp, _query, _index} -> bp 36 end) 37 38 querys_and_indices = 39 Enum.map(valid_queries, fn 40 {:ok, _bp, query, index} -> {query, index} 41 end) 42 43 blueprints 44 |> Absinthe.Pipeline.BatchResolver.run(schema: schema) 45 |> Enum.zip(querys_and_indices) 46 |> Enum.map(fn {bp, {query, i}} -> 47 {i, build_result(bp, query)} 48 end) 49 end 50 51 defp build_invalid_results(invalid_queries) do 52 Enum.map(invalid_queries, fn {:error, bp, query, i} -> 53 {i, build_result(bp, query)} 54 end) 55 end 56 57 defp build_result(bp, query) do 58 case Absinthe.Pipeline.run(bp, result_pipeline(query)) do 59 {:ok, bp, _} -> 60 bp 61 62 _ -> 63 %{result: %{errors: ["could not produce a valid JSON result"]}} 64 end 65 end 66 67 defp prepare(queries) do 68 for {query, i} <- Enum.with_index(queries) do 69 case Absinthe.Pipeline.run(query.document, validation_pipeline(query)) do 70 {:ok, bp, _} -> 71 case bp.execution.validation_errors do 72 [] -> 73 {:ok, bp, query, i} 74 75 _ -> 76 {:error, bp, query, i} 77 end 78 79 {:error, bp, _} -> 80 {:error, bp, query, i} 81 end 82 end 83 end 84 85 defp build_pipelines(queries, conn_info, config) do 86 for query <- queries do 87 query 88 |> Map.update!(:raw_options, &([jump_phases: false] ++ &1)) 89 |> Request.Query.add_pipeline(conn_info, config) 90 end 91 end 92 93 defp validation_pipeline(%{pipeline: pipeline}) do 94 pipeline 95 |> Absinthe.Pipeline.before(Absinthe.Phase.Document.Execution.Resolution) 96 end 97 98 defp result_pipeline(%{pipeline: pipeline}) do 99 pipeline 100 |> Absinthe.Pipeline.from(Absinthe.Phase.Document.Execution.Resolution) 101 |> Enum.drop(1) 102 end 103 end