Class: Graphlient::Query::Serializer

Inherits:
Object
  • Object
show all
Includes:
Arguments, Directives, Evaluator, Fragments, Scalars
Defined in:
lib/graphlient/query/serializer.rb,
lib/graphlient/query/serializer/scalars.rb,
lib/graphlient/query/serializer/arguments.rb,
lib/graphlient/query/serializer/evaluator.rb,
lib/graphlient/query/serializer/fragments.rb,
lib/graphlient/query/serializer/directives.rb

Overview

Builds a GraphQL query string from a DSL block. Composed from focused concern modules; Query is a thin public wrapper.

Defined Under Namespace

Modules: Arguments, Directives, Evaluator, Fragments, Scalars

Constant Summary collapse

ROOT_NODES =
%w[query mutation subscription].freeze
SPREAD_REQUIRES_NAME_OR_ON =

Raised when spread is called with neither a fragment name nor on:.

'spread requires a fragment name (`spread :InvoiceFields`) or an inline ' \
'type condition (`spread on: :PaidInvoice { ... }`).'.freeze
SPREAD_NAME_TAKES_NO_BLOCK =

Raised when a named spread is given a block (a named spread has no selection set).

'a named fragment spread takes no block; for an inline fragment use ' \
'`spread on: :Type { ... }`.'.freeze

Constants included from Directives

Directives::DIRECTIVE_PREFIX

Constants included from Fragments

Fragments::FRAGMENT_DEFINITION

Constants included from Scalars

Scalars::BUILT_IN_SCALAR_TYPES

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Scalars

included

Constructor Details

#initialize(&block) ⇒ Serializer

Returns a new instance of Serializer.



31
32
33
34
35
36
37
# File 'lib/graphlient/query/serializer.rb', line 31

def initialize(&block)
  @indents   = 0
  @query_str = ''
  @variables = {}
  @fragments = {}
  evaluate(&block) if block
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_name, *args, &block) ⇒ Object



86
87
88
89
90
91
92
93
94
# File 'lib/graphlient/query/serializer.rb', line 86

def method_missing(method_name, *args, &block)
  if fragment?(method_name)
    append_node("...#{resolve_fragment_constant(method_name)}".to_sym, args, &block)
  elsif directive?(method_name)
    Directive.new(method_name, args.first || {})
  else
    append_node(method_name, args, &block)
  end
end

Instance Attribute Details

#query_strObject

Returns the value of attribute query_str.



29
30
31
# File 'lib/graphlient/query/serializer.rb', line 29

def query_str
  @query_str
end

Instance Method Details

#fragment(name, on:, &block) ⇒ Object

Inline fragment definition -- collected and appended after the main query. fragment(:InvoiceFields, on: :Invoice) { id; fee_in_cents }



81
82
83
84
# File 'lib/graphlient/query/serializer.rb', line 81

def fragment(name, on:, &block)
  body = self.class.new(&block).query_str.strip
  @fragments[name] = "fragment #{name} on #{on} {\n#{body}\n}"
end

#respond_to_missing?(method_name, include_private = false) ⇒ Boolean

Returns:

  • (Boolean)


96
97
98
# File 'lib/graphlient/query/serializer.rb', line 96

def respond_to_missing?(method_name, include_private = false)
  super
end

#spread(*args, on: nil, &block) ⇒ Object

Fragment spread OR inline fragment -- one consistent entry point.

Named fragment spread: ...FragmentName [@directive ...] spread :InvoiceFields spread :InvoiceFields, _skip(if: :x) # -> ...InvoiceFields @skip(if: $x)

Inline fragment / type condition: ... on Type [@directive ...] { fields } spread on: :PaidInvoice { amount_paid } # -> ... on PaidInvoice { amountPaid } spread on: :DraftInvoice, _skip(if: :skip) { draft_id } spread on: :Invoice # bare type condition, no block

A single verb covers both GraphQL forms; on: is the same keyword used by fragment(name, on:), keeping the DSL consistent (and leaving room for a future spread(:X).skip(...) chaining form without a breaking change).



69
70
71
72
73
74
75
76
77
# File 'lib/graphlient/query/serializer.rb', line 69

def spread(*args, on: nil, &block)
  directives = args.select { |a| a.is_a?(Directive) }
  if on
    append_inline_fragment(on, directives, &block)
  else
    append_named_spread(args, directives, &block)
  end
  @query_str << "\n#{indent}"
end

#to_sObject

Full output: main query string + any inline fragment definitions.



40
41
42
43
44
# File 'lib/graphlient/query/serializer.rb', line 40

def to_s
  parts = [query_str.strip]
  parts.concat(@fragments.values) unless @fragments.empty?
  parts.join("\n\n")
end