Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-12-01 15:09:17 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-12-01 15:09:17 +0300
commit7b2635a55d4e87431bae752bd44c6fd2d2657b03 (patch)
tree88182aabb51a167e10f6c3a6d404b2247613047f /spec/support/graphql
parenta7704bf16a51a8c993215a69db17232e3f246b8e (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/support/graphql')
-rw-r--r--spec/support/graphql/arguments.rb70
-rw-r--r--spec/support/graphql/field_inspection.rb35
-rw-r--r--spec/support/graphql/field_selection.rb73
3 files changed, 178 insertions, 0 deletions
diff --git a/spec/support/graphql/arguments.rb b/spec/support/graphql/arguments.rb
new file mode 100644
index 00000000000..d8c334c2ca4
--- /dev/null
+++ b/spec/support/graphql/arguments.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+module Graphql
+ class Arguments
+ delegate :blank?, :empty?, to: :to_h
+
+ def initialize(values)
+ @values = values.compact
+ end
+
+ def to_h
+ @values
+ end
+
+ def ==(other)
+ to_h == other&.to_h
+ end
+
+ alias_method :eql, :==
+
+ def to_s
+ return '' if empty?
+
+ @values.map do |name, value|
+ value_str = as_graphql_literal(value)
+
+ "#{GraphqlHelpers.fieldnamerize(name.to_s)}: #{value_str}"
+ end.join(", ")
+ end
+
+ def as_graphql_literal(value)
+ self.class.as_graphql_literal(value)
+ end
+
+ # Transform values to GraphQL literal arguments.
+ # Use symbol for Enum values
+ def self.as_graphql_literal(value)
+ case value
+ when ::Graphql::Arguments then "{#{value}}"
+ when Array then "[#{value.map { |v| as_graphql_literal(v) }.join(',')}]"
+ when Hash then "{#{new(value)}}"
+ when Integer, Float, Symbol then value.to_s
+ when String then "\"#{value.gsub(/"/, '\\"')}\""
+ when nil then 'null'
+ when true then 'true'
+ when false then 'false'
+ else
+ value.to_graphql_value
+ end
+ rescue NoMethodError
+ raise ArgumentError, "Cannot represent #{value} as GraphQL literal"
+ end
+
+ def merge(other)
+ self.class.new(@values.merge(other.to_h))
+ end
+
+ def +(other)
+ if blank?
+ other
+ elsif other.blank?
+ self
+ elsif other.is_a?(String)
+ [to_s, other].compact.join(', ')
+ else
+ merge(other)
+ end
+ end
+ end
+end
diff --git a/spec/support/graphql/field_inspection.rb b/spec/support/graphql/field_inspection.rb
new file mode 100644
index 00000000000..f39ba751141
--- /dev/null
+++ b/spec/support/graphql/field_inspection.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+module Graphql
+ class FieldInspection
+ def initialize(field)
+ @field = field
+ end
+
+ def nested_fields?
+ !scalar? && !enum?
+ end
+
+ def scalar?
+ type.kind.scalar?
+ end
+
+ def enum?
+ type.kind.enum?
+ end
+
+ def type
+ @type ||= begin
+ field_type = @field.type.respond_to?(:to_graphql) ? @field.type.to_graphql : @field.type
+
+ # The type could be nested. For example `[GraphQL::STRING_TYPE]`:
+ # - List
+ # - String!
+ # - String
+ field_type = field_type.of_type while field_type.respond_to?(:of_type)
+
+ field_type
+ end
+ end
+ end
+end
diff --git a/spec/support/graphql/field_selection.rb b/spec/support/graphql/field_selection.rb
new file mode 100644
index 00000000000..e2a3334acac
--- /dev/null
+++ b/spec/support/graphql/field_selection.rb
@@ -0,0 +1,73 @@
+# frozen_string_literal: true
+
+module Graphql
+ class FieldSelection
+ delegate :empty?, :blank?, :to_h, to: :selection
+ delegate :size, to: :paths
+
+ attr_reader :selection
+
+ def initialize(selection = {})
+ @selection = selection.to_h
+ end
+
+ def to_s
+ serialize_field_selection(selection)
+ end
+
+ def paths
+ selection.flat_map do |field, subselection|
+ paths_in([field], subselection)
+ end
+ end
+
+ private
+
+ def paths_in(path, leaves)
+ return [path] if leaves.nil?
+
+ leaves.to_a.flat_map do |k, v|
+ paths_in([k], v).map { |tail| path + tail }
+ end
+ end
+
+ def serialize_field_selection(hash, level = 0)
+ indent = ' ' * level
+
+ hash.map do |field, subselection|
+ if subselection.nil?
+ "#{indent}#{field}"
+ else
+ subfields = serialize_field_selection(subselection, level + 1)
+ "#{indent}#{field} {\n#{subfields}\n#{indent}}"
+ end
+ end.join("\n")
+ end
+
+ NO_SKIP = ->(_name, _field) { false }
+
+ def self.select_fields(type, skip = NO_SKIP, parent_types = Set.new, max_depth = 3)
+ return new if max_depth <= 0
+
+ new(type.fields.flat_map do |name, field|
+ next [] if skip[name, field]
+
+ inspected = ::Graphql::FieldInspection.new(field)
+ singular_field_type = inspected.type
+
+ # If field type is the same as parent type, then we're hitting into
+ # mutual dependency. Break it from infinite recursion
+ next [] if parent_types.include?(singular_field_type)
+
+ if inspected.nested_fields?
+ subselection = select_fields(singular_field_type, skip, parent_types | [type], max_depth - 1)
+ next [] if subselection.empty?
+
+ [[name, subselection.to_h]]
+ else
+ [[name, nil]]
+ end
+ end)
+ end
+ end
+end