1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
|
# frozen_string_literal: true
require 'json'
require 'apollo_upload_server/wrappers/uploaded_file'
module ApolloUploadServer
class GraphQLDataBuilder
OutOfBounds = Class.new(ArgumentError)
def initialize(strict_mode: false)
@strict_mode = strict_mode
end
def call(params)
operations = JSON.parse(params['operations'])
file_mapper = JSON.parse(params['map'])
return nil if operations.nil? || file_mapper.nil?
if operations.is_a?(Hash)
single_transformation(file_mapper, operations, params)
else
{ '_json' => multiple_transformation(file_mapper, operations, params) }
end
end
private
def single_transformation(file_mapper, operations, params)
operations = operations.dup
file_mapper.each do |file_index, paths|
paths.each do |path|
splited_path = path.split('.')
# splited_path => 'variables.input.profile_photo'; splited_path[0..-2] => ['variables', 'input']
# dig from first to penultimate key, and merge last key with value as file
field = get_parent_field(operations, splited_path)
assign_file(field, splited_path, params[file_index])
end
end
operations
end
def multiple_transformation(file_mapper, operations, params)
operations = operations.dup
file_mapper.each do |file_index, paths|
paths.each do |path|
splited_path = path.split('.')
# dig from second to penultimate key, and merge last key with value as file to operation with first key index
field = operations[splited_path.first.to_i].dig(*splited_path[1..-2])
assign_file(field, splited_path, params[file_index])
end
end
operations
end
def verify_array_index!(path, index, size)
return unless @strict_mode
return if 0 <= index && index < size
raise OutOfBounds, "Path #{path.join('.')} maps to out-of-bounds index: #{index}"
end
def get_parent_field(operations, splited_path)
# returns parent element of file field
splited_path[0..-2].inject(operations) do |element, key|
case element
when Array
element[Integer(key)]
else
element[key]
end
end
end
def assign_file(field, splited_path, file)
wrapped_file = Wrappers::UploadedFile.new(file)
if field.is_a? Hash
field.merge!(splited_path.last => wrapped_file)
elsif field.is_a? Array
index = parse_array_index(splited_path)
verify_array_index!(splited_path, index, field.size)
field[index] = wrapped_file
end
end
def parse_array_index(path)
return path.last.to_i unless @strict_mode
Integer(path.last)
rescue ArgumentError
raise OutOfBounds, "Not a valid path to an array value: #{path.join('.')}"
end
end
end
|