graphlyte 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/graphlyte/arguments/set.rb +12 -8
- data/lib/graphlyte/arguments/value.rb +5 -11
- data/lib/graphlyte/builder.rb +9 -3
- data/lib/graphlyte/directive.rb +21 -0
- data/lib/graphlyte/field.rb +32 -5
- data/lib/graphlyte/inline_fragment.rb +29 -0
- data/lib/graphlyte/query.rb +49 -8
- data/lib/graphlyte/refinements/string_refinement.rb +2 -2
- data/lib/graphlyte/schema/parser.rb +362 -208
- data/lib/graphlyte/schema/types/base.rb +41 -1
- data/lib/graphlyte/types.rb +2 -2
- data/lib/graphlyte.rb +14 -1
- metadata +4 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 97c3b9e1d17580b4d94cf3ffaa9f7291d8ff10c9441a9c2270a378daad39f977
         | 
| 4 | 
            +
              data.tar.gz: f3586e4ea3a92e0ac462b92a17115a81a8c64e6643c296861072a23543ae2b92
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: a4dd27faa45576150659090362b94f30297faad8a1a1d5758480e63359bd74e92a30960e70fad8aa446c60e1540dd384458590d5f6cc00eb49c9aa09b44d6659
         | 
| 7 | 
            +
              data.tar.gz: 1887884979b8f92cc8c1b145c782363b7be9e907fc3541cee5e103a4e901d07261f1a6f69aa0aafcce337efda5e5de4a3950fa4803f17a074f4cc6bbd0555ace
         | 
| @@ -26,15 +26,15 @@ module Graphlyte | |
| 26 26 | 
             
                    variables
         | 
| 27 27 | 
             
                  end
         | 
| 28 28 |  | 
| 29 | 
            -
                  def to_h( | 
| 29 | 
            +
                  def to_h(raw = false)
         | 
| 30 30 | 
             
                    return {} unless values && !values.empty?
         | 
| 31 31 | 
             
                    values.inject({}) do |memo, (k, v)|
         | 
| 32 32 | 
             
                      if v.is_a?(Array)
         | 
| 33 | 
            -
                        memo[k.to_s.to_camel_case] = v.map( | 
| 33 | 
            +
                        memo[k.to_s.to_camel_case] = v.map { |value| value.to_s(raw) }
         | 
| 34 34 | 
             
                      elsif v.is_a?(Set)
         | 
| 35 35 | 
             
                        memo[k.to_s.to_camel_case] = v.to_h
         | 
| 36 36 | 
             
                      else
         | 
| 37 | 
            -
                        memo[k.to_s.to_camel_case] = v.to_s
         | 
| 37 | 
            +
                        memo[k.to_s.to_camel_case] = v.to_s(raw)
         | 
| 38 38 | 
             
                      end
         | 
| 39 39 | 
             
                      memo
         | 
| 40 40 | 
             
                    end
         | 
| @@ -42,7 +42,15 @@ module Graphlyte | |
| 42 42 |  | 
| 43 43 | 
             
                  def to_s(inner = false)
         | 
| 44 44 | 
             
                    return "" unless values && !values.empty?
         | 
| 45 | 
            -
                    arr =  | 
| 45 | 
            +
                    arr = stringify_arguments
         | 
| 46 | 
            +
                    return arr.join(", ") if inner
         | 
| 47 | 
            +
                    "(#{arr.join(", ")})"
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  private 
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                  def stringify_arguments
         | 
| 53 | 
            +
                    values.map do |k,v|
         | 
| 46 54 | 
             
                      if v.is_a?(Array)
         | 
| 47 55 | 
             
                        "#{k.to_s.to_camel_case}: [#{v.map(&:to_s).join(", ")}]"
         | 
| 48 56 | 
             
                      elsif v.is_a?(Set)
         | 
| @@ -51,12 +59,8 @@ module Graphlyte | |
| 51 59 | 
             
                        "#{k.to_s.to_camel_case}: #{v.to_s}"
         | 
| 52 60 | 
             
                      end
         | 
| 53 61 | 
             
                    end
         | 
| 54 | 
            -
                    return arr.join(", ") if inner
         | 
| 55 | 
            -
                    "(#{arr.join(", ")})"
         | 
| 56 62 | 
             
                  end
         | 
| 57 63 |  | 
| 58 | 
            -
                  private 
         | 
| 59 | 
            -
             | 
| 60 64 | 
             
                  def expand_arguments(data)
         | 
| 61 65 | 
             
                    data.inject({}) do |memo, (k, v)|
         | 
| 62 66 | 
             
                      if v.is_a?(Array)
         | 
| @@ -4,17 +4,11 @@ module Graphlyte | |
| 4 4 | 
             
                class Value
         | 
| 5 5 | 
             
                  using Refinements::StringRefinement
         | 
| 6 6 |  | 
| 7 | 
            -
                  attr_reader :value | 
| 7 | 
            +
                  attr_reader :value
         | 
| 8 8 |  | 
| 9 | 
            -
                  def initialize(value | 
| 9 | 
            +
                  def initialize(value)
         | 
| 10 10 | 
             
                    raise ArgumentError, "Hash not allowed in this context" if value.is_a? Hash
         | 
| 11 | 
            -
                     | 
| 12 | 
            -
                      @value = value.value
         | 
| 13 | 
            -
                      @default = value.default
         | 
| 14 | 
            -
                    else
         | 
| 15 | 
            -
                      @value = value
         | 
| 16 | 
            -
                      @default = default
         | 
| 17 | 
            -
                    end
         | 
| 11 | 
            +
                    @value = value
         | 
| 18 12 | 
             
                  end
         | 
| 19 13 |  | 
| 20 14 | 
             
                  def symbol?
         | 
| @@ -25,10 +19,10 @@ module Graphlyte | |
| 25 19 | 
             
                    value.is_a? Schema::Types::Base
         | 
| 26 20 | 
             
                  end
         | 
| 27 21 |  | 
| 28 | 
            -
                  def to_s
         | 
| 22 | 
            +
                  def to_s(raw = false)
         | 
| 29 23 | 
             
                    return "$#{value.to_s.to_camel_case}" if value.is_a? Symbol
         | 
| 30 24 | 
             
                    return value if value.is_a? Numeric
         | 
| 31 | 
            -
                    return "\"#{value}\"" if value.is_a?  | 
| 25 | 
            +
                    return "\"#{value}\"" if value.is_a?(String) && !raw
         | 
| 32 26 | 
             
                    return "null" if value.nil?
         | 
| 33 27 | 
             
                    return "$#{value.placeholder.to_camel_case}" if value.is_a? Schema::Types::Base
         | 
| 34 28 | 
             
                    value.to_s
         | 
    
        data/lib/graphlyte/builder.rb
    CHANGED
    
    | @@ -8,19 +8,25 @@ module Graphlyte | |
| 8 8 | 
             
                end
         | 
| 9 9 |  | 
| 10 10 | 
             
                def <<(buildable)
         | 
| 11 | 
            -
                  raise "Must pass a Fieldset or Fragment" unless [Fragment, Fieldset].include?(buildable.class)
         | 
| 11 | 
            +
                  raise "Must pass a Fieldset or Fragment" unless [Fragment, Fieldset, InlineFragment].include?(buildable.class)
         | 
| 12 12 |  | 
| 13 13 | 
             
                  @fields.concat(buildable.fields) if buildable.class.eql? Fieldset
         | 
| 14 14 |  | 
| 15 15 | 
             
                  # todo: handle fragments better, it's not a field
         | 
| 16 | 
            -
                  @fields << buildable if buildable.class | 
| 16 | 
            +
                  @fields << buildable if [InlineFragment, Fragment].include? buildable.class
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def remove(field_symbol)
         | 
| 20 | 
            +
                  @fields.reject! do |field|
         | 
| 21 | 
            +
                    field.name == field_symbol.to_s
         | 
| 22 | 
            +
                  end
         | 
| 17 23 | 
             
                end
         | 
| 18 24 |  | 
| 19 25 | 
             
                def method_missing(method, fieldset_or_hargs=nil, hargs={}, &block)
         | 
| 20 26 | 
             
                  # todo: camel case method
         | 
| 21 27 |  | 
| 22 28 | 
             
                  # hack for ruby bug in lower versions
         | 
| 23 | 
            -
                  if [Fieldset, Fragment].include?(fieldset_or_hargs.class)
         | 
| 29 | 
            +
                  if [Fieldset, Fragment, InlineFragment].include?(fieldset_or_hargs.class)
         | 
| 24 30 | 
             
                    field = Field.new(method, fieldset_or_hargs, hargs)
         | 
| 25 31 | 
             
                  else
         | 
| 26 32 | 
             
                    field = Field.new(method, Fieldset.empty, fieldset_or_hargs)
         | 
| @@ -0,0 +1,21 @@ | |
| 1 | 
            +
            require_relative 'arguments/set'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Graphlyte
         | 
| 4 | 
            +
              class Directive
         | 
| 5 | 
            +
                attr_reader :name, :inputs
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def initialize(name, **hargs)
         | 
| 8 | 
            +
                  @name = name
         | 
| 9 | 
            +
                  @inputs = Arguments::Set.new(hargs)
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                def inflate(indent, string, field: nil)
         | 
| 13 | 
            +
                  # add directive after fieldname?
         | 
| 14 | 
            +
                  string += ' ' * indent
         | 
| 15 | 
            +
                  string += "#{field} " if field
         | 
| 16 | 
            +
                  string += "@#{name}"
         | 
| 17 | 
            +
                  string += @inputs.to_s unless @inputs.to_s.empty?
         | 
| 18 | 
            +
                  string
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
            end
         | 
    
        data/lib/graphlyte/field.rb
    CHANGED
    
    | @@ -1,25 +1,39 @@ | |
| 1 1 | 
             
            require_relative "./arguments/set"
         | 
| 2 | 
            +
            require_relative 'directive'
         | 
| 2 3 | 
             
            require_relative "./refinements/string_refinement"
         | 
| 3 4 | 
             
            module Graphlyte
         | 
| 4 5 | 
             
              class Field
         | 
| 5 6 | 
             
                using Refinements::StringRefinement
         | 
| 6 7 |  | 
| 7 | 
            -
                attr_reader :name, :fieldset, :inputs, : | 
| 8 | 
            +
                attr_reader :name, :fieldset, :inputs, :directive
         | 
| 8 9 |  | 
| 9 | 
            -
                def initialize(name, fieldset, hargs, inputs: Arguments::Set.new(hargs))
         | 
| 10 | 
            +
                def initialize(name, fieldset, hargs, directive: nil, inputs: Arguments::Set.new(hargs))
         | 
| 10 11 | 
             
                  @name = name.to_s.to_camel_case
         | 
| 11 12 | 
             
                  @fieldset = fieldset
         | 
| 12 13 | 
             
                  @inputs = inputs
         | 
| 13 14 | 
             
                  @alias = nil
         | 
| 15 | 
            +
                  @directive = directive
         | 
| 14 16 | 
             
                end
         | 
| 15 17 |  | 
| 16 18 | 
             
                def atomic?
         | 
| 17 19 | 
             
                  fieldset.empty?
         | 
| 18 | 
            -
                end | 
| 20 | 
            +
                end
         | 
| 19 21 |  | 
| 20 22 | 
             
                def alias(name, &block)
         | 
| 21 23 | 
             
                  @alias = name
         | 
| 22 | 
            -
                   | 
| 24 | 
            +
                  if block
         | 
| 25 | 
            +
                    fieldset.builder.>.instance_eval(&block)
         | 
| 26 | 
            +
                  else
         | 
| 27 | 
            +
                    self
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                def include(**hargs, &block)
         | 
| 32 | 
            +
                  make_directive('include', **hargs, &block)
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                def skip(**hargs, &block)
         | 
| 36 | 
            +
                  make_directive('skip', **hargs, &block)
         | 
| 23 37 | 
             
                end
         | 
| 24 38 |  | 
| 25 39 | 
             
                def to_s(indent=0)
         | 
| @@ -27,12 +41,25 @@ module Graphlyte | |
| 27 41 | 
             
                  actual_indent = ("\s" * indent) * 2
         | 
| 28 42 | 
             
                  if @alias
         | 
| 29 43 | 
             
                    str += "#{actual_indent}#{@alias}: #{name}"
         | 
| 30 | 
            -
                    str += inputs.to_s.empty? ? "()" : inputs.to_s | 
| 44 | 
            +
                    str += inputs.to_s.empty? ? "()" : inputs.to_s
         | 
| 45 | 
            +
                  elsif @directive
         | 
| 46 | 
            +
                    str = @directive.inflate(indent * 2, str, field: name)
         | 
| 31 47 | 
             
                  else
         | 
| 32 48 | 
             
                    str += "#{actual_indent}#{name}#{inputs.to_s}"
         | 
| 33 49 | 
             
                  end
         | 
| 34 50 | 
             
                  str += " {\n#{fieldset.to_s(indent + 1)}\n#{actual_indent}}" unless atomic?
         | 
| 35 51 | 
             
                  str
         | 
| 36 52 | 
             
                end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                private
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                def method_missing(symbol, **hargs, &block)
         | 
| 57 | 
            +
                  make_directive(symbol.to_s, **hargs, &block)
         | 
| 58 | 
            +
                end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                def make_directive(name, **hargs, &block)
         | 
| 61 | 
            +
                  @directive = Directive.new(name, **hargs)
         | 
| 62 | 
            +
                  fieldset.builder.>.instance_eval(&block) if block
         | 
| 63 | 
            +
                end
         | 
| 37 64 | 
             
              end
         | 
| 38 65 | 
             
            end
         | 
| @@ -0,0 +1,29 @@ | |
| 1 | 
            +
            require_relative "./fieldset"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Graphlyte
         | 
| 4 | 
            +
              class InlineFragment < Fieldset
         | 
| 5 | 
            +
                attr_reader :directive
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def self.from_directive(directive, **hargs)
         | 
| 8 | 
            +
                  new(nil, directive: directive, **hargs)
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def initialize(model = nil, directive: nil, **hargs)
         | 
| 12 | 
            +
                  @directive = directive
         | 
| 13 | 
            +
                  super(model, **hargs)
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                def to_s(indent=0)
         | 
| 17 | 
            +
                  actual_indent = ("\s" * indent) * 2
         | 
| 18 | 
            +
                  string = '... '
         | 
| 19 | 
            +
                  string += "on #{model_name}" if model_name
         | 
| 20 | 
            +
                  inflate_indent = model_name ? 1 : 0
         | 
| 21 | 
            +
                  string = directive.inflate(inflate_indent, string) if directive
         | 
| 22 | 
            +
                  string += " {\n"
         | 
| 23 | 
            +
                  string += super(indent + 1)
         | 
| 24 | 
            +
                  string += "\n#{actual_indent}}"
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  "#{actual_indent}#{string}"
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
            end
         | 
    
        data/lib/graphlyte/query.rb
    CHANGED
    
    | @@ -1,6 +1,35 @@ | |
| 1 1 | 
             
            require_relative "./refinements/string_refinement"
         | 
| 2 2 | 
             
            require "json"
         | 
| 3 3 | 
             
            module Graphlyte
         | 
| 4 | 
            +
              class Selector
         | 
| 5 | 
            +
                def initialize(selector)
         | 
| 6 | 
            +
                  @selector_tokens = selector.split('.')
         | 
| 7 | 
            +
                end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                def modify(fields, selector_tokens = @selector_tokens, &block)
         | 
| 10 | 
            +
                  token = selector_tokens.shift
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  if token == '*'
         | 
| 13 | 
            +
                    fields.each do |field|
         | 
| 14 | 
            +
                      modify(field.fieldset.fields, [token], &block)
         | 
| 15 | 
            +
                      field.fieldset.builder.instance_eval(&block) unless field.fieldset.fields.empty?
         | 
| 16 | 
            +
                    end
         | 
| 17 | 
            +
                  else
         | 
| 18 | 
            +
                    needle = fields.find do |field|
         | 
| 19 | 
            +
                      field.name == token
         | 
| 20 | 
            +
                    end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                    raise "#{token} not found in query" unless needle
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                    if selector_tokens.size.zero?
         | 
| 25 | 
            +
                      needle.fieldset.builder.instance_eval(&block)
         | 
| 26 | 
            +
                    else
         | 
| 27 | 
            +
                      modify(needle.fieldset.fields, selector_tokens, &block)
         | 
| 28 | 
            +
                    end
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
             | 
| 4 33 | 
             
              class Query < Fieldset
         | 
| 5 34 | 
             
                using Refinements::StringRefinement
         | 
| 6 35 | 
             
                attr_reader :name, :type
         | 
| @@ -11,6 +40,10 @@ module Graphlyte | |
| 11 40 | 
             
                  super(**hargs)
         | 
| 12 41 | 
             
                end
         | 
| 13 42 |  | 
| 43 | 
            +
                def at(selector, &block)
         | 
| 44 | 
            +
                  Selector.new(selector).modify(fields, &block)
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
             | 
| 14 47 | 
             
                def placeholders
         | 
| 15 48 | 
             
                  flatten_variables(builder.>>).map do |value|
         | 
| 16 49 | 
             
                    unless value.formal?
         | 
| @@ -19,8 +52,9 @@ module Graphlyte | |
| 19 52 | 
             
                      str = ":#{value.value.placeholder} of #{value.value.name}"
         | 
| 20 53 | 
             
                    end
         | 
| 21 54 |  | 
| 22 | 
            -
                    if value.default
         | 
| 23 | 
            -
                      str += " with default  | 
| 55 | 
            +
                    if value.value.default
         | 
| 56 | 
            +
                      str += " with default "
         | 
| 57 | 
            +
                      value.value.default.merge!(str)
         | 
| 24 58 | 
             
                    end
         | 
| 25 59 | 
             
                    str
         | 
| 26 60 | 
             
                  end.join("\n")
         | 
| @@ -33,11 +67,16 @@ module Graphlyte | |
| 33 67 | 
             
                  str = "#{type} #{query_name}"
         | 
| 34 68 | 
             
                  unless types.empty?
         | 
| 35 69 | 
             
                    type_new = types.map do |type_arr|
         | 
| 36 | 
            -
                      "$#{type_arr[0].to_camel_case}: #{type_arr[1]}"
         | 
| 70 | 
            +
                      type_str = "$#{type_arr[0].to_camel_case}: #{type_arr[1]}"
         | 
| 71 | 
            +
                      unless type_arr[2].nil?
         | 
| 72 | 
            +
                        type_str << " = "
         | 
| 73 | 
            +
                        type_arr[2].merge!(type_str)
         | 
| 74 | 
            +
                      end
         | 
| 75 | 
            +
                      type_str
         | 
| 37 76 | 
             
                    end
         | 
| 38 77 | 
             
                    str += "(#{type_new.join(", ")})"
         | 
| 39 78 | 
             
                  end
         | 
| 40 | 
            -
                  { query: "#{str} #{to_s(1)}", variables: Arguments::Set.new(hargs).to_h }.to_json
         | 
| 79 | 
            +
                  { query: "#{str} #{to_s(1)}", variables: Arguments::Set.new(hargs).to_h(true) }.to_json
         | 
| 41 80 | 
             
                end
         | 
| 42 81 |  | 
| 43 82 | 
             
                def to_s(indent=0)
         | 
| @@ -59,12 +98,12 @@ module Graphlyte | |
| 59 98 | 
             
                        memo <<  "[#{merge_variable_types(var.value, hargs).first}]"
         | 
| 60 99 | 
             
                      end
         | 
| 61 100 | 
             
                    else
         | 
| 62 | 
            -
                      memo << [var.value.placeholder, var.value.name]
         | 
| 101 | 
            +
                      memo << [var.value.placeholder, var.value.name, var.value.default]
         | 
| 63 102 | 
             
                    end
         | 
| 64 103 | 
             
                    memo
         | 
| 65 104 | 
             
                  end
         | 
| 66 105 | 
             
                end
         | 
| 67 | 
            -
             | 
| 106 | 
            +
             | 
| 68 107 | 
             
                def format_fragments
         | 
| 69 108 | 
             
                  str = "\n"
         | 
| 70 109 | 
             
                  flatten(builder.>>).each do |_, fragment|
         | 
| @@ -77,8 +116,9 @@ module Graphlyte | |
| 77 116 |  | 
| 78 117 | 
             
                def flatten_variables(fields, variables=[])
         | 
| 79 118 | 
             
                  fields.each do |field|
         | 
| 80 | 
            -
                    variables.concat field.inputs.extract_variables unless field.class | 
| 81 | 
            -
                    if field.class. | 
| 119 | 
            +
                    variables.concat field.inputs.extract_variables unless [InlineFragment, Fragment].include? field.class
         | 
| 120 | 
            +
                    variables.concat field.directive.inputs.extract_variables if field.class == InlineFragment && field.directive
         | 
| 121 | 
            +
                    if [InlineFragment, Fragment].include? field.class
         | 
| 82 122 | 
             
                      flatten_variables(field.fields, variables)
         | 
| 83 123 | 
             
                    else
         | 
| 84 124 | 
             
                      flatten_variables(field.fieldset.fields, variables)
         | 
| @@ -89,6 +129,7 @@ module Graphlyte | |
| 89 129 |  | 
| 90 130 | 
             
                def flatten(fields, new_fields = {})
         | 
| 91 131 | 
             
                  fields.each do |field|
         | 
| 132 | 
            +
                    next if field.class == InlineFragment
         | 
| 92 133 | 
             
                    if field.class.eql?(Fragment)
         | 
| 93 134 | 
             
                      new_fields[field.fragment] = field
         | 
| 94 135 | 
             
                      unless field.empty?
         | 
| @@ -10,11 +10,11 @@ module Graphlyte | |
| 10 10 | 
             
                    def to_camel_case
         | 
| 11 11 | 
             
                      start_of_string = match(/(^_+)/)&.[](0)
         | 
| 12 12 | 
             
                      end_of_string = match(/(_+$)/)&.[](0)
         | 
| 13 | 
            -
             | 
| 13 | 
            +
             | 
| 14 14 | 
             
                      middle = split("_").reject(&:empty?).inject([]) do |memo, str|
         | 
| 15 15 | 
             
                        memo << (memo.empty? ? str : str.capitalize)
         | 
| 16 16 | 
             
                      end.join("")
         | 
| 17 | 
            -
             | 
| 17 | 
            +
             | 
| 18 18 | 
             
                      "#{start_of_string}#{middle}#{end_of_string}"
         | 
| 19 19 | 
             
                    end 
         | 
| 20 20 | 
             
                  end
         | 
| @@ -13,18 +13,31 @@ module Graphlyte | |
| 13 13 | 
             
                    fields
         | 
| 14 14 | 
             
                  end
         | 
| 15 15 |  | 
| 16 | 
            +
                  def skip_fieldset
         | 
| 17 | 
            +
                    expect(:FIELDSET)
         | 
| 18 | 
            +
                    parse_fields
         | 
| 19 | 
            +
                    need(:END_FIELDSET)
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
             | 
| 16 22 | 
             
                  def parse_field
         | 
| 17 23 | 
             
                    alias_field = expect(:ALIAS)
         | 
| 18 24 | 
             
                    if token = expect(:FRAGMENT_REF)
         | 
| 19 25 | 
             
                      raise "Can't find fragment #{token[0][1]}" unless fragments_dictionary[token[0][1]]
         | 
| 20 26 | 
             
                      fragments_dictionary[token[0][1]]
         | 
| 21 | 
            -
                    elsif  | 
| 27 | 
            +
                    elsif expect(:INLINE_FRAGMENT)
         | 
| 28 | 
            +
                      field = parse_inline_fragment
         | 
| 29 | 
            +
                    elsif expect(:FIELDSET)
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                    elsif (field = expect(:FIELD_NAME))
         | 
| 22 32 | 
             
                      args = parse_args
         | 
| 23 | 
            -
                       | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 33 | 
            +
                      directive = parse_directive
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                      if builder = parse_fieldset_into_builder
         | 
| 36 | 
            +
                        need(:END_FIELDSET)
         | 
| 37 | 
            +
                        fieldset = Fieldset.new(builder: builder)
         | 
| 38 | 
            +
                        field = Field.new(field[0][1], fieldset, args, directive: directive)
         | 
| 26 39 | 
             
                      else
         | 
| 27 | 
            -
                        field = Field.new(field[0][1], Fieldset.empty, args)
         | 
| 40 | 
            +
                        field = Field.new(field[0][1], Fieldset.empty, args, directive: directive)
         | 
| 28 41 | 
             
                      end
         | 
| 29 42 |  | 
| 30 43 | 
             
                      if alias_field
         | 
| @@ -35,10 +48,29 @@ module Graphlyte | |
| 35 48 | 
             
                    end
         | 
| 36 49 | 
             
                  end
         | 
| 37 50 |  | 
| 38 | 
            -
                  def  | 
| 39 | 
            -
                     | 
| 51 | 
            +
                  def parse_inline_fragment
         | 
| 52 | 
            +
                    model_name = expect(:MODEL_NAME)&.dig(0, 1)
         | 
| 53 | 
            +
                    directive = parse_directive
         | 
| 54 | 
            +
                    inputs = directive ? (parse_args || {}) : {}
         | 
| 55 | 
            +
                    fields = expect(:FIELDSET) ? parse_fields : []
         | 
| 56 | 
            +
                    need(:END_FIELDSET)
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                    InlineFragment.new(model_name, directive: directive, builder: Builder.new(fields), **inputs)
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                  def parse_directive
         | 
| 62 | 
            +
                    if token = expect(:DIRECTIVE)
         | 
| 63 | 
            +
                      inputs = parse_args || {}
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                      Directive.new(token[0][1], **inputs)
         | 
| 66 | 
            +
                    end
         | 
| 67 | 
            +
                  end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                  def parse_fieldset_into_builder
         | 
| 70 | 
            +
                    fields = []
         | 
| 71 | 
            +
                    if expect(:FIELDSET)
         | 
| 40 72 | 
             
                      fields = parse_fields
         | 
| 41 | 
            -
                       | 
| 73 | 
            +
                      Builder.new(fields)
         | 
| 42 74 | 
             
                    end
         | 
| 43 75 | 
             
                  end
         | 
| 44 76 |  | 
| @@ -51,7 +83,7 @@ module Graphlyte | |
| 51 83 | 
             
                  end
         | 
| 52 84 |  | 
| 53 85 | 
             
                  def parse_default
         | 
| 54 | 
            -
                    if expect(: | 
| 86 | 
            +
                    if expect(:DEFAULT_VALUE)
         | 
| 55 87 | 
             
                      value = parse_value
         | 
| 56 88 | 
             
                      need(:END_DEFAULT_VALUE)
         | 
| 57 89 | 
             
                      value
         | 
| @@ -63,11 +95,7 @@ module Graphlyte | |
| 63 95 | 
             
                      defaults = parse_default
         | 
| 64 96 | 
             
                      key = token[0][1]
         | 
| 65 97 | 
             
                      hash = {}
         | 
| 66 | 
            -
                       | 
| 67 | 
            -
                        hash[key] = value
         | 
| 68 | 
            -
                      else
         | 
| 69 | 
            -
                        hash[key] = Graphlyte::Arguments::Value.new(value, defaults)
         | 
| 70 | 
            -
                      end
         | 
| 98 | 
            +
                      hash[key] = value
         | 
| 71 99 | 
             
                      hash
         | 
| 72 100 | 
             
                    elsif (token = expect(:SPECIAL_ARG_KEY)) && (value = parse_value)
         | 
| 73 101 | 
             
                      defaults = parse_default
         | 
| @@ -76,7 +104,8 @@ module Graphlyte | |
| 76 104 | 
             
                      if [Array, Hash].include?(value.class)
         | 
| 77 105 | 
             
                        arg[token[0][1]] = value
         | 
| 78 106 | 
             
                      else
         | 
| 79 | 
            -
                         | 
| 107 | 
            +
                        new_val = Schema::Types::Base.new(value, token[0][1], defaults)
         | 
| 108 | 
            +
                        arg[token[0][1]] = new_val
         | 
| 80 109 | 
             
                      end
         | 
| 81 110 | 
             
                      @special_args.merge!(arg)
         | 
| 82 111 | 
             
                      arg
         | 
| @@ -89,13 +118,12 @@ module Graphlyte | |
| 89 118 | 
             
                    elsif token = expect(:SPECIAL_ARG_REF)
         | 
| 90 119 | 
             
                      ref = token[0][1]
         | 
| 91 120 | 
             
                      raise "Can't find ref $#{ref}" unless @special_args[ref]
         | 
| 92 | 
            -
                       | 
| 93 | 
            -
                      Arguments::Value.new(Graphlyte::TYPES.send(value.value, ref.to_sym), value.default)
         | 
| 121 | 
            +
                      @special_args[ref]
         | 
| 94 122 | 
             
                    elsif token = expect(:SPECIAL_ARG_VAL)
         | 
| 95 123 | 
             
                      token[0][1]
         | 
| 96 | 
            -
                    elsif token = expect(: | 
| 124 | 
            +
                    elsif token = expect(:ARG_HASH)
         | 
| 97 125 | 
             
                      parse_arg_hash
         | 
| 98 | 
            -
                    elsif expect(: | 
| 126 | 
            +
                    elsif expect(:ARG_ARRAY)
         | 
| 99 127 | 
             
                      parse_arg_array
         | 
| 100 128 | 
             
                    end
         | 
| 101 129 | 
             
                  end
         | 
| @@ -108,10 +136,15 @@ module Graphlyte | |
| 108 136 |  | 
| 109 137 | 
             
                  def parse_arg_hash
         | 
| 110 138 | 
             
                    if (key = expect(:ARG_KEY)) && (value = parse_value)
         | 
| 111 | 
            -
                      need(:ARG_HASH_END)
         | 
| 112 139 | 
             
                      hash = {}
         | 
| 113 140 | 
             
                      hash[key[0][1]] = value
         | 
| 114 141 | 
             
                      hash
         | 
| 142 | 
            +
                      if new_hash = parse_arg_hash
         | 
| 143 | 
            +
                        hash.merge!(new_hash)
         | 
| 144 | 
            +
                      else
         | 
| 145 | 
            +
                        need(:ARG_HASH_END)
         | 
| 146 | 
            +
                        hash
         | 
| 147 | 
            +
                      end
         | 
| 115 148 | 
             
                    end
         | 
| 116 149 | 
             
                  end
         | 
| 117 150 |  | 
| @@ -133,6 +166,10 @@ module Graphlyte | |
| 133 166 | 
             
                    end
         | 
| 134 167 | 
             
                  end
         | 
| 135 168 |  | 
| 169 | 
            +
                  def tokens?
         | 
| 170 | 
            +
                    !tokens[position].nil?
         | 
| 171 | 
            +
                  end
         | 
| 172 | 
            +
             | 
| 136 173 | 
             
                  def need(*required_tokens)
         | 
| 137 174 | 
             
                    upcoming = tokens[position, required_tokens.size]
         | 
| 138 175 | 
             
                    expect(*required_tokens) or raise "Unexpected tokens. Expected #{required_tokens.inspect} but got #{upcoming.inspect}"
         | 
| @@ -153,7 +190,7 @@ module Graphlyte | |
| 153 190 | 
             
                    if current_ref
         | 
| 154 191 | 
             
                      exists = sorted.any? do |frags|
         | 
| 155 192 | 
             
                        frags.find do |el|
         | 
| 156 | 
            -
                          el[0] == : | 
| 193 | 
            +
                          el[0] == :FRAGMENT && el[1] == current_ref[1]
         | 
| 157 194 | 
             
                        end
         | 
| 158 195 | 
             
                      end
         | 
| 159 196 | 
             
                      if exists
         | 
| @@ -171,11 +208,11 @@ module Graphlyte | |
| 171 208 |  | 
| 172 209 | 
             
                  def take_fragments
         | 
| 173 210 | 
             
                    aggregate = @tokens.inject({taking: false, idx: 0,  fragments: []}) do |memo, token_arr|
         | 
| 174 | 
            -
                      if token_arr[0] == : | 
| 211 | 
            +
                      if token_arr[0] == :END_FIELDSET
         | 
| 175 212 | 
             
                        memo[:fragments][memo[:idx]] << token_arr
         | 
| 176 213 | 
             
                        memo[:taking] = false
         | 
| 177 214 | 
             
                        memo[:idx] += 1
         | 
| 178 | 
            -
                      elsif token_arr[0] === : | 
| 215 | 
            +
                      elsif token_arr[0] === :FRAGMENT
         | 
| 179 216 | 
             
                        memo[:fragments][memo[:idx]] = [token_arr]
         | 
| 180 217 | 
             
                        memo[:taking] = true
         | 
| 181 218 | 
             
                      elsif memo[:taking]
         | 
| @@ -185,6 +222,35 @@ module Graphlyte | |
| 185 222 | 
             
                    end
         | 
| 186 223 | 
             
                    aggregate[:fragments]
         | 
| 187 224 | 
             
                  end
         | 
| 225 | 
            +
             | 
| 226 | 
            +
                  def fetch_fragments(tokens = @tokens.dup, fragment_tokens = [], memo = { active: false, starts: 0, ends: 0, idx: 0 })
         | 
| 227 | 
            +
                    token_arr = tokens.shift
         | 
| 228 | 
            +
                    return fragment_tokens if token_arr.nil?
         | 
| 229 | 
            +
             | 
| 230 | 
            +
             | 
| 231 | 
            +
                    if memo[:active] == true
         | 
| 232 | 
            +
                      fragment_tokens[memo[:idx]] << token_arr
         | 
| 233 | 
            +
                    end
         | 
| 234 | 
            +
             | 
| 235 | 
            +
                    if token_arr[0] == :END_FIELDSET && memo[:active] == true
         | 
| 236 | 
            +
                      memo[:ends] += 1
         | 
| 237 | 
            +
                      fragment_tokens[memo[:idx]] << token_arr if memo[:starts] == memo[:ends]
         | 
| 238 | 
            +
             | 
| 239 | 
            +
                      memo[:active] = false
         | 
| 240 | 
            +
                      memo[:ends] = 0
         | 
| 241 | 
            +
                      memo[:starts] = 0
         | 
| 242 | 
            +
                      memo[:idx] += 1
         | 
| 243 | 
            +
                    elsif token_arr[0] == :FRAGMENT
         | 
| 244 | 
            +
                      memo[:active] = true
         | 
| 245 | 
            +
                      memo[:starts] += 1
         | 
| 246 | 
            +
                      fragment_tokens[memo[:idx]] = [token_arr]
         | 
| 247 | 
            +
                    elsif token_arr[0] == :FIELDSET && memo[:active] == true
         | 
| 248 | 
            +
                      memo[:starts] += 1
         | 
| 249 | 
            +
                    end
         | 
| 250 | 
            +
             | 
| 251 | 
            +
             | 
| 252 | 
            +
                    fetch_fragments(tokens, fragment_tokens, memo)
         | 
| 253 | 
            +
                  end
         | 
| 188 254 | 
             
                end
         | 
| 189 255 |  | 
| 190 256 | 
             
                class FragmentParser
         | 
| @@ -204,12 +270,16 @@ module Graphlyte | |
| 204 270 | 
             
                  end
         | 
| 205 271 |  | 
| 206 272 | 
             
                  def parse_fragment
         | 
| 207 | 
            -
                    if token = expect(: | 
| 273 | 
            +
                    if token = expect(:FRAGMENT)
         | 
| 208 274 | 
             
                      parse_args
         | 
| 209 | 
            -
                      builder =  | 
| 210 | 
            -
             | 
| 275 | 
            +
                      if builder = parse_fieldset_into_builder
         | 
| 276 | 
            +
                        fragment = Fragment.new(token[0][1], token[0][2], builder: builder)
         | 
| 277 | 
            +
                        need(:END_FIELDSET) if tokens?
         | 
| 278 | 
            +
                      elsif fields = parse_fields
         | 
| 279 | 
            +
                        builder = Builder.new(fields)
         | 
| 280 | 
            +
                        fragment = Fragment.new(token[0][1], token[0][2], builder: builder)
         | 
| 281 | 
            +
                      end
         | 
| 211 282 | 
             
                      @fragments_dictionary[token[0][1]] = fragment
         | 
| 212 | 
            -
                      need(:END_FRAGMENT)
         | 
| 213 283 | 
             
                    end
         | 
| 214 284 | 
             
                  end
         | 
| 215 285 | 
             
                end
         | 
| @@ -226,41 +296,42 @@ module Graphlyte | |
| 226 296 |  | 
| 227 297 | 
             
                  def initialize(tokens)
         | 
| 228 298 | 
             
                    @tokens = tokens
         | 
| 229 | 
            -
             | 
| 299 | 
            +
             | 
| 300 | 
            +
                    @fragment_tokens = sort_fragments([], fetch_fragments)
         | 
| 230 301 | 
             
                    @fragments_dictionary = {}
         | 
| 231 302 | 
             
                    @fragments_dictionary = @fragment_tokens.any? ? FragmentParser.new(@fragment_tokens).parse_fragments : {}
         | 
| 232 303 | 
             
                    @position = 0
         | 
| 233 304 | 
             
                  end
         | 
| 234 305 |  | 
| 235 306 | 
             
                  def parse
         | 
| 236 | 
            -
                    if token = expect(: | 
| 237 | 
            -
                       | 
| 238 | 
            -
                    elsif  | 
| 239 | 
            -
                       | 
| 307 | 
            +
                    if token = expect(:EXPRESSION)
         | 
| 308 | 
            +
                      parse_expression(token[0][1], token[0][2])
         | 
| 309 | 
            +
                    elsif expect(:FRAGMENT)
         | 
| 310 | 
            +
                      skip_fragments
         | 
| 311 | 
            +
                      parse
         | 
| 240 312 | 
             
                    else
         | 
| 241 313 | 
             
                      raise "INVALID"
         | 
| 242 314 | 
             
                    end
         | 
| 243 315 | 
             
                  end
         | 
| 244 316 |  | 
| 245 | 
            -
                  def  | 
| 246 | 
            -
                     | 
| 247 | 
            -
                    builder = Builder.new parse_fields
         | 
| 248 | 
            -
                    query = Query.new(name, :query, builder: builder)
         | 
| 249 | 
            -
                    need(:END_QUERY)
         | 
| 250 | 
            -
                    query
         | 
| 317 | 
            +
                  def skip_fragments
         | 
| 318 | 
            +
                    skip_fieldset
         | 
| 251 319 | 
             
                  end
         | 
| 252 320 |  | 
| 253 | 
            -
                  def  | 
| 254 | 
            -
                     | 
| 255 | 
            -
                     | 
| 256 | 
            -
                     | 
| 257 | 
            -
                     | 
| 321 | 
            +
                  def parse_expression(type, name)
         | 
| 322 | 
            +
                    parse_args
         | 
| 323 | 
            +
                    fields = []
         | 
| 324 | 
            +
                    builder = parse_fieldset_into_builder
         | 
| 325 | 
            +
                    need(:END_FIELDSET)
         | 
| 326 | 
            +
                    query = Query.new(name, type.to_sym, builder: builder)
         | 
| 327 | 
            +
                    query
         | 
| 258 328 | 
             
                  end
         | 
| 259 329 | 
             
                end
         | 
| 260 330 |  | 
| 331 | 
            +
                class LexerError < StandardError; end
         | 
| 332 | 
            +
             | 
| 261 333 | 
             
                class Lexer
         | 
| 262 334 | 
             
                  attr_reader :stack, :scanner
         | 
| 263 | 
            -
             | 
| 264 335 | 
             
                  def initialize(gql, scanner: StringScanner.new(gql))
         | 
| 265 336 | 
             
                    @original_string = gql
         | 
| 266 337 | 
             
                    @scanner = scanner
         | 
| @@ -268,211 +339,290 @@ module Graphlyte | |
| 268 339 | 
             
                  end
         | 
| 269 340 |  | 
| 270 341 | 
             
                  SPECIAL_ARG_REGEX = /^\s*(?:(?<![\"\{]))([\w\!\[\]]+)(?:(?![\"\}]))/
         | 
| 271 | 
            -
                  SIMPLE_EXPRESSION = /(query|mutation|fragment)\s*\w+\s*on\w*.*\{\s*\n*[.|\w\s]*\}/
         | 
| 272 | 
            -
                  START_MAP = {
         | 
| 273 | 
            -
                    'query' => :START_QUERY,
         | 
| 274 | 
            -
                    'mutation' => :START_MUTATION,
         | 
| 275 | 
            -
                    'fragment' => :START_FRAGMENT
         | 
| 276 | 
            -
                  }
         | 
| 277 342 |  | 
| 278 343 | 
             
                  def tokenize
         | 
| 279 344 | 
             
                    until scanner.eos?
         | 
| 280 | 
            -
                       | 
| 281 | 
            -
             | 
| 282 | 
            -
             | 
| 283 | 
            -
             | 
| 284 | 
            -
             | 
| 285 | 
            -
             | 
| 286 | 
            -
             | 
| 287 | 
            -
             | 
| 288 | 
            -
             | 
| 289 | 
            -
             | 
| 290 | 
            -
             | 
| 291 | 
            -
                         | 
| 292 | 
            -
             | 
| 293 | 
            -
             | 
| 294 | 
            -
             | 
| 295 | 
            -
                          @tokens << [:END_EXPRESSION_SHOULDNT_GET_THIS]
         | 
| 296 | 
            -
                        else
         | 
| 297 | 
            -
                          advance
         | 
| 298 | 
            -
                        end
         | 
| 299 | 
            -
                      when :fragment
         | 
| 300 | 
            -
                        if scanner.scan /\s*\}\s*/
         | 
| 301 | 
            -
                          @tokens << [:END_FRAGMENT]
         | 
| 302 | 
            -
                          pop_state
         | 
| 303 | 
            -
                          pop_context
         | 
| 304 | 
            -
                        elsif scanner.check /^\s*\{\s*/
         | 
| 305 | 
            -
                          if get_context == :field
         | 
| 306 | 
            -
                            push_state :field
         | 
| 307 | 
            -
                            push_context :field
         | 
| 308 | 
            -
                          else
         | 
| 309 | 
            -
                            scanner.scan /^\s*\{\s*/
         | 
| 310 | 
            -
                            push_context :field
         | 
| 311 | 
            -
                          end
         | 
| 312 | 
            -
                        else
         | 
| 313 | 
            -
                          handle_field
         | 
| 314 | 
            -
                        end
         | 
| 315 | 
            -
                      when :mutation
         | 
| 316 | 
            -
                        if scanner.scan /\}/
         | 
| 317 | 
            -
                          @tokens << [:END_MUTATION]
         | 
| 318 | 
            -
                          pop_state
         | 
| 319 | 
            -
                          pop_context
         | 
| 320 | 
            -
                        elsif scanner.check /^\s*\{\s*$/
         | 
| 321 | 
            -
                          if get_context == :field
         | 
| 322 | 
            -
                            push_state :field
         | 
| 323 | 
            -
                          else
         | 
| 324 | 
            -
                            scanner.scan /^\s*\{\s*$/
         | 
| 325 | 
            -
                            push_context :field
         | 
| 326 | 
            -
                          end
         | 
| 327 | 
            -
                        else
         | 
| 328 | 
            -
                          handle_field
         | 
| 329 | 
            -
                        end
         | 
| 330 | 
            -
                      when :query
         | 
| 331 | 
            -
                        if scanner.scan /\s*\}\s*/
         | 
| 332 | 
            -
                          @tokens << [:END_QUERY]
         | 
| 333 | 
            -
                          pop_state
         | 
| 334 | 
            -
                          pop_context
         | 
| 335 | 
            -
                        elsif scanner.check /^\s*\{\s*/
         | 
| 336 | 
            -
                          if get_context == :field
         | 
| 337 | 
            -
                            push_state :field
         | 
| 338 | 
            -
                            push_context :field
         | 
| 339 | 
            -
                          else
         | 
| 340 | 
            -
                            scanner.scan /^\s*\{\s*/
         | 
| 341 | 
            -
                            push_context :field
         | 
| 342 | 
            -
                          end
         | 
| 345 | 
            +
                      tokenize_objects
         | 
| 346 | 
            +
                    end
         | 
| 347 | 
            +
             | 
| 348 | 
            +
                    @tokens
         | 
| 349 | 
            +
                  end
         | 
| 350 | 
            +
             | 
| 351 | 
            +
                  def tokenize_objects
         | 
| 352 | 
            +
                    case state
         | 
| 353 | 
            +
                    when :default # the stack is empty, can only process top level fragments or expressions
         | 
| 354 | 
            +
                      if scanner.scan %r{\s*fragment\s*(\w+)\s*on\s*(\w+)}
         | 
| 355 | 
            +
                        @tokens << [:FRAGMENT, scanner[1], scanner[2]]
         | 
| 356 | 
            +
                        push_context :fragments
         | 
| 357 | 
            +
                        # check for a fieldset
         | 
| 358 | 
            +
                        if scanner.check %r[\s*{]
         | 
| 359 | 
            +
                          tokenize_fieldset
         | 
| 343 360 | 
             
                        else
         | 
| 344 | 
            -
                           | 
| 361 | 
            +
                          scanner.scan /\(/
         | 
| 362 | 
            +
                          @tokens << [:START_ARGS]
         | 
| 363 | 
            +
                          push_state :arguments
         | 
| 345 364 | 
             
                        end
         | 
| 346 | 
            -
                       | 
| 347 | 
            -
                         | 
| 348 | 
            -
             | 
| 349 | 
            -
             | 
| 350 | 
            -
             | 
| 351 | 
            -
             | 
| 352 | 
            -
             | 
| 353 | 
            -
             | 
| 354 | 
            -
             | 
| 365 | 
            +
                      elsif scanner.check /\{/
         | 
| 366 | 
            +
                        push_context :fieldset
         | 
| 367 | 
            +
             | 
| 368 | 
            +
                        tokenize_fieldset
         | 
| 369 | 
            +
                      elsif scanner.scan %r{^(\w+) (\w+)}
         | 
| 370 | 
            +
                        @tokens << [:EXPRESSION, scanner[1], scanner[2]]
         | 
| 371 | 
            +
                        push_context :expression
         | 
| 372 | 
            +
                        # check for a fieldset
         | 
| 373 | 
            +
                        if scanner.check %r[\s*{]
         | 
| 374 | 
            +
                          tokenize_fieldset
         | 
| 355 375 | 
             
                        else
         | 
| 356 | 
            -
                           | 
| 376 | 
            +
                          scanner.scan /\(/
         | 
| 377 | 
            +
                          @tokens << [:START_ARGS]
         | 
| 378 | 
            +
                          push_state :arguments
         | 
| 357 379 | 
             
                        end
         | 
| 358 | 
            -
                       | 
| 359 | 
            -
                         | 
| 360 | 
            -
             | 
| 361 | 
            -
                         | 
| 362 | 
            -
             | 
| 363 | 
            -
                        if scanner.scan /\s*\)\s*/
         | 
| 364 | 
            -
                          @tokens << [:END_ARGS]
         | 
| 365 | 
            -
                          pop_state
         | 
| 366 | 
            -
                        elsif scanner.scan /\=/
         | 
| 367 | 
            -
                          @tokens << [:START_DEFAULT_VALUE]
         | 
| 368 | 
            -
                          push_state :argument_defaults
         | 
| 369 | 
            -
                        elsif scanner.scan /,/
         | 
| 370 | 
            -
                          #
         | 
| 371 | 
            -
                        else
         | 
| 372 | 
            -
                          handle_shared_arguments
         | 
| 380 | 
            +
                      elsif scanner.check /\s*\}/
         | 
| 381 | 
            +
                        if get_context == :fragments
         | 
| 382 | 
            +
                          end_fragment
         | 
| 383 | 
            +
                        elsif get_context == :expression
         | 
| 384 | 
            +
                          end_expression
         | 
| 373 385 | 
             
                        end
         | 
| 374 | 
            -
                       | 
| 375 | 
            -
                         | 
| 376 | 
            -
                          @tokens << [:END_DEFAULT_VALUE]
         | 
| 377 | 
            -
                          pop_state
         | 
| 378 | 
            -
                          pop_state
         | 
| 379 | 
            -
                        else
         | 
| 380 | 
            -
                          push_state :argument_defaults
         | 
| 381 | 
            -
                          handle_shared_arguments
         | 
| 382 | 
            -
                        end
         | 
| 383 | 
            -
                      when :special_args
         | 
| 384 | 
            -
                        handle_special_args
         | 
| 386 | 
            +
                      else
         | 
| 387 | 
            +
                        advance
         | 
| 385 388 | 
             
                      end
         | 
| 389 | 
            +
                    when :fieldset
         | 
| 390 | 
            +
                      tokenize_fields
         | 
| 391 | 
            +
                    when :arguments
         | 
| 392 | 
            +
                      tokenize_arguments
         | 
| 393 | 
            +
                    when :argument_defaults
         | 
| 394 | 
            +
                      tokenize_shared_arguments
         | 
| 395 | 
            +
                    when :hash_arguments
         | 
| 396 | 
            +
                      tokenize_hash_arguments
         | 
| 397 | 
            +
                    when :array_arguments
         | 
| 398 | 
            +
                      tokenize_array_arguments
         | 
| 399 | 
            +
                    when :special_args
         | 
| 400 | 
            +
                      tokenize_special_arguments
         | 
| 401 | 
            +
                    when :inline_fragment
         | 
| 402 | 
            +
                      tokenize_inline_fragment
         | 
| 386 403 | 
             
                    end
         | 
| 387 | 
            -
                    @tokens
         | 
| 388 404 | 
             
                  end
         | 
| 389 405 |  | 
| 390 | 
            -
                   | 
| 406 | 
            +
                  def check_for_last(regex = /\s*\}/)
         | 
| 407 | 
            +
                    scanner.check regex
         | 
| 408 | 
            +
                  end
         | 
| 391 409 |  | 
| 392 | 
            -
                  def  | 
| 393 | 
            -
                     | 
| 394 | 
            -
             | 
| 395 | 
            -
             | 
| 396 | 
            -
             | 
| 397 | 
            -
                     | 
| 398 | 
            -
             | 
| 399 | 
            -
             | 
| 400 | 
            -
             | 
| 401 | 
            -
             | 
| 402 | 
            -
                       | 
| 403 | 
            -
             | 
| 404 | 
            -
                       | 
| 405 | 
            -
                    elsif scanner.scan  | 
| 406 | 
            -
                      @tokens << [: | 
| 407 | 
            -
             | 
| 408 | 
            -
                       | 
| 409 | 
            -
                      @tokens << [:FIELD_NAME, scanner[1]]
         | 
| 410 | 
            -
                      pop_context
         | 
| 411 | 
            -
                      # we need to pop state if we are nested in a field, and not in the query context
         | 
| 412 | 
            -
                      pop_state if get_context == :field
         | 
| 413 | 
            -
                    elsif scanner.scan /\s*(\w+)\s*/
         | 
| 414 | 
            -
                      @tokens << [:FIELD_NAME, scanner[1]]
         | 
| 415 | 
            -
                    elsif scanner.scan /^\s*\(/
         | 
| 416 | 
            -
                      @tokens << [:START_ARGS]
         | 
| 417 | 
            -
                      push_state :arguments
         | 
| 410 | 
            +
                  def check_for_final
         | 
| 411 | 
            +
                    scanner.check /\s*\}(?!\s*\})/
         | 
| 412 | 
            +
                  end
         | 
| 413 | 
            +
             | 
| 414 | 
            +
                  def check_for_not_last
         | 
| 415 | 
            +
                    scanner.check /\s*\}(?=\s*\})/
         | 
| 416 | 
            +
                  end
         | 
| 417 | 
            +
             | 
| 418 | 
            +
                  def tokenize_inline_fragment
         | 
| 419 | 
            +
                    if scanner.scan /on (\w+)/
         | 
| 420 | 
            +
                      @tokens << [:MODEL_NAME, scanner[1]]
         | 
| 421 | 
            +
             | 
| 422 | 
            +
                      pop_state
         | 
| 423 | 
            +
                    elsif scanner.scan /@(\w+)/
         | 
| 424 | 
            +
                      @tokens << [:DIRECTIVE, scanner[1]]
         | 
| 425 | 
            +
             | 
| 426 | 
            +
                      pop_state
         | 
| 418 427 | 
             
                    else
         | 
| 428 | 
            +
                      # throw an error here?
         | 
| 419 429 | 
             
                      advance
         | 
| 420 430 | 
             
                    end
         | 
| 421 431 | 
             
                  end
         | 
| 422 432 |  | 
| 423 | 
            -
                  def  | 
| 433 | 
            +
                  def end_fieldset
         | 
| 434 | 
            +
                    scanner.scan /\s*\}/
         | 
| 435 | 
            +
                    @tokens << [:END_FIELDSET]
         | 
| 436 | 
            +
                    pop_state
         | 
| 437 | 
            +
                  end
         | 
| 438 | 
            +
             | 
| 439 | 
            +
                  def end_arguments
         | 
| 440 | 
            +
                    scanner.scan /\s*\)/
         | 
| 441 | 
            +
                    @tokens << [:END_ARGS]
         | 
| 442 | 
            +
                    pop_state
         | 
| 443 | 
            +
                  end
         | 
| 444 | 
            +
             | 
| 445 | 
            +
                  def end_fragment
         | 
| 446 | 
            +
                    scanner.scan /\s*\}/
         | 
| 447 | 
            +
                    @tokens << [:END_FRAGMENT]
         | 
| 448 | 
            +
                    pop_state
         | 
| 449 | 
            +
                    pop_context
         | 
| 450 | 
            +
                  end
         | 
| 451 | 
            +
             | 
| 452 | 
            +
                  def end_expression
         | 
| 453 | 
            +
                    scanner.scan /\s*\}/
         | 
| 454 | 
            +
                    @tokens << [:END_EXPRESSION]
         | 
| 455 | 
            +
                    pop_state
         | 
| 456 | 
            +
                    pop_context
         | 
| 457 | 
            +
                  end
         | 
| 458 | 
            +
             | 
| 459 | 
            +
                  # to tired to figure out why this is right now
         | 
| 460 | 
            +
                  def tokenize_argument_defaults
         | 
| 461 | 
            +
                    if scanner.scan /\)/
         | 
| 462 | 
            +
                      @tokens << [:END_DEFAULT_VALUE]
         | 
| 463 | 
            +
                      pop_state
         | 
| 464 | 
            +
                    else
         | 
| 465 | 
            +
                      tokenize_shared_arguments
         | 
| 466 | 
            +
                    end
         | 
| 467 | 
            +
                  end
         | 
| 468 | 
            +
             | 
| 469 | 
            +
                  def tokenize_special_arguments
         | 
| 470 | 
            +
                    if scanner.check SPECIAL_ARG_REGEX
         | 
| 471 | 
            +
                      scanner.scan SPECIAL_ARG_REGEX
         | 
| 472 | 
            +
             | 
| 473 | 
            +
                      @tokens << [:SPECIAL_ARG_VAL, scanner[1]]
         | 
| 474 | 
            +
             | 
| 475 | 
            +
                      pop_state
         | 
| 476 | 
            +
             | 
| 477 | 
            +
                      end_arguments if check_for_last(/\s*\)/)
         | 
| 478 | 
            +
                    else
         | 
| 479 | 
            +
                      # revisit this.. should we throw an error here?
         | 
| 480 | 
            +
                      pop_state
         | 
| 481 | 
            +
                      raise LexerError, "why can't we parse #{scanner.peek(5)}"
         | 
| 482 | 
            +
                    end
         | 
| 483 | 
            +
                  end
         | 
| 484 | 
            +
             | 
| 485 | 
            +
                  def tokenize_array_arguments
         | 
| 486 | 
            +
                    if scanner.scan /\]/
         | 
| 487 | 
            +
                      @tokens << [:ARG_ARRAY_END]
         | 
| 488 | 
            +
             | 
| 489 | 
            +
                      pop_state
         | 
| 490 | 
            +
                      # if check_for_last(')')
         | 
| 491 | 
            +
                      #   pop_state
         | 
| 492 | 
            +
                      # end
         | 
| 493 | 
            +
                    else
         | 
| 494 | 
            +
                      tokenize_shared_arguments
         | 
| 495 | 
            +
                    end
         | 
| 496 | 
            +
                  end
         | 
| 497 | 
            +
             | 
| 498 | 
            +
                  def tokenize_hash_arguments
         | 
| 499 | 
            +
                    if scanner.scan /\}/
         | 
| 500 | 
            +
                      @tokens << [:ARG_HASH_END]
         | 
| 501 | 
            +
             | 
| 502 | 
            +
                      pop_state
         | 
| 503 | 
            +
                      # if this is the last argument in the list, maybe get back to the field scope?
         | 
| 504 | 
            +
                      # if check_for_last(')')
         | 
| 505 | 
            +
                      #   pop_state
         | 
| 506 | 
            +
                      # end
         | 
| 507 | 
            +
                    else
         | 
| 508 | 
            +
                      tokenize_shared_arguments
         | 
| 509 | 
            +
                    end
         | 
| 510 | 
            +
                  end
         | 
| 511 | 
            +
             | 
| 512 | 
            +
                  def tokenize_arguments
         | 
| 513 | 
            +
                    # pop argument state if arguments are finished
         | 
| 514 | 
            +
                    if scanner.scan %r{\)}
         | 
| 515 | 
            +
                      @tokens << [:END_ARGS]
         | 
| 516 | 
            +
             | 
| 517 | 
            +
                      pop_state
         | 
| 518 | 
            +
                    # something(argument: $argument = true)
         | 
| 519 | 
            +
                    #                               ^
         | 
| 520 | 
            +
                    elsif scanner.scan %r{=}
         | 
| 521 | 
            +
                      @tokens << [:DEFAULT_VALUE]
         | 
| 522 | 
            +
             | 
| 523 | 
            +
                      push_state :argument_defaults
         | 
| 524 | 
            +
                    # noop, should expect this, but not important
         | 
| 525 | 
            +
                    elsif scanner.scan %r{,}
         | 
| 526 | 
            +
                      nil
         | 
| 527 | 
            +
                    else
         | 
| 528 | 
            +
                      tokenize_shared_arguments
         | 
| 529 | 
            +
                    end
         | 
| 530 | 
            +
                  end
         | 
| 531 | 
            +
             | 
| 532 | 
            +
                  def tokenize_shared_arguments
         | 
| 424 533 | 
             
                    if scanner.scan /^(\w+):/
         | 
| 425 534 | 
             
                      @tokens << [:ARG_KEY, scanner[1]]
         | 
| 426 | 
            -
                    elsif scanner.scan  | 
| 427 | 
            -
                      @tokens << [: | 
| 535 | 
            +
                    elsif scanner.scan %r[{]
         | 
| 536 | 
            +
                      @tokens << [:ARG_HASH]
         | 
| 537 | 
            +
             | 
| 428 538 | 
             
                      push_state :hash_arguments
         | 
| 429 | 
            -
                    elsif scanner.scan /\ | 
| 430 | 
            -
                      @tokens << [: | 
| 539 | 
            +
                    elsif scanner.scan /\[/
         | 
| 540 | 
            +
                      @tokens << [:ARG_ARRAY]
         | 
| 541 | 
            +
             | 
| 431 542 | 
             
                      push_state :array_arguments
         | 
| 432 | 
            -
                    elsif scanner.scan  | 
| 543 | 
            +
                    elsif scanner.scan %r{"(.*?)"}
         | 
| 433 544 | 
             
                      @tokens << [:ARG_STRING_VALUE, scanner[1]]
         | 
| 434 | 
            -
             | 
| 545 | 
            +
             | 
| 546 | 
            +
                      end_arguments if check_for_last(/\s*\)/)
         | 
| 547 | 
            +
                    elsif scanner.scan /(\d+\.\d+)/
         | 
| 435 548 | 
             
                      @tokens << [:ARG_FLOAT_VALUE, scanner[1].to_f]
         | 
| 436 | 
            -
             | 
| 549 | 
            +
             | 
| 550 | 
            +
                      end_arguments if check_for_last(/\s*\)/)
         | 
| 551 | 
            +
                    elsif scanner.scan /(\d+)/
         | 
| 437 552 | 
             
                      @tokens << [:ARG_NUM_VALUE, scanner[1].to_i]
         | 
| 438 | 
            -
             | 
| 439 | 
            -
                       | 
| 440 | 
            -
             | 
| 553 | 
            +
             | 
| 554 | 
            +
                      end_arguments if check_for_last(/\s*\)/)
         | 
| 555 | 
            +
                    elsif scanner.scan /(true|false)/
         | 
| 556 | 
            +
                      @tokens << [:ARG_BOOL_VALUE, (scanner[1] == 'true')]
         | 
| 557 | 
            +
             | 
| 558 | 
            +
                      end_arguments if check_for_last(/\s*\)/)
         | 
| 441 559 | 
             
                    elsif scanner.scan /\$(\w+):/
         | 
| 442 560 | 
             
                      @tokens << [:SPECIAL_ARG_KEY, scanner[1]]
         | 
| 561 | 
            +
             | 
| 443 562 | 
             
                      push_state :special_args
         | 
| 444 563 | 
             
                    elsif scanner.scan /\$(\w+)/
         | 
| 445 564 | 
             
                      @tokens << [:SPECIAL_ARG_REF, scanner[1]]
         | 
| 446 | 
            -
                    else
         | 
| 447 | 
            -
                      advance
         | 
| 448 | 
            -
                    end
         | 
| 449 | 
            -
                  end
         | 
| 450 565 |  | 
| 451 | 
            -
             | 
| 452 | 
            -
                     | 
| 453 | 
            -
                       | 
| 454 | 
            -
             | 
| 566 | 
            +
                      end_arguments if check_for_last(/\s*\)/)
         | 
| 567 | 
            +
                    elsif scanner.scan /,/
         | 
| 568 | 
            +
                      # no-op
         | 
| 569 | 
            +
                    elsif check_for_last(/\s*\)/)
         | 
| 570 | 
            +
                      @tokens << [:END_DEFAULT_VALUE] if state == :argument_defaults
         | 
| 571 | 
            +
                      end_arguments
         | 
| 455 572 | 
             
                      pop_state
         | 
| 456 573 | 
             
                    else
         | 
| 457 | 
            -
                       | 
| 574 | 
            +
                      advance
         | 
| 458 575 | 
             
                    end
         | 
| 459 576 | 
             
                  end
         | 
| 460 577 |  | 
| 461 | 
            -
                  def  | 
| 462 | 
            -
                    if scanner. | 
| 463 | 
            -
                       | 
| 464 | 
            -
             | 
| 578 | 
            +
                  def tokenize_fields
         | 
| 579 | 
            +
                    if scanner.check %r[{]
         | 
| 580 | 
            +
                      tokenize_fieldset
         | 
| 581 | 
            +
                    # ... on Model - or - ... @directive
         | 
| 582 | 
            +
                    elsif scanner.scan %r{\.{3}\s}
         | 
| 583 | 
            +
                      @tokens << [:INLINE_FRAGMENT]
         | 
| 584 | 
            +
                      push_state :inline_fragment
         | 
| 585 | 
            +
                    # @directive
         | 
| 586 | 
            +
                    elsif scanner.scan %r{@(\w+)}
         | 
| 587 | 
            +
                      @tokens << [:DIRECTIVE, scanner[1]]
         | 
| 588 | 
            +
                    # ...fragmentReference (check for last since it is a field literal)
         | 
| 589 | 
            +
                    elsif scanner.scan /\.{3}(\w+)/
         | 
| 590 | 
            +
                      @tokens << [:FRAGMENT_REF, scanner[1]]
         | 
| 591 | 
            +
             | 
| 592 | 
            +
                      end_fieldset while check_for_last && state == :fieldset
         | 
| 593 | 
            +
                    # alias:
         | 
| 594 | 
            +
                    elsif scanner.scan %r{(\w+):}
         | 
| 595 | 
            +
                      @tokens << [:ALIAS, scanner[1]]
         | 
| 596 | 
            +
                    # fieldLiteral
         | 
| 597 | 
            +
                    elsif scanner.scan %r{(\w+)}
         | 
| 598 | 
            +
                      @tokens << [:FIELD_NAME, scanner[1]]
         | 
| 599 | 
            +
             | 
| 600 | 
            +
                      end_fieldset while check_for_last && state == :fieldset
         | 
| 601 | 
            +
                    # (arguments: true)
         | 
| 602 | 
            +
                    elsif scanner.scan /^\s*\(/
         | 
| 603 | 
            +
                      @tokens << [:START_ARGS]
         | 
| 604 | 
            +
             | 
| 605 | 
            +
                      push_state :arguments
         | 
| 606 | 
            +
                    elsif check_for_final
         | 
| 607 | 
            +
                      if get_context == :fragments
         | 
| 608 | 
            +
                        end_fragment
         | 
| 609 | 
            +
                      elsif get_context == :expression
         | 
| 610 | 
            +
                        end_expression
         | 
| 611 | 
            +
                      else
         | 
| 612 | 
            +
                        advance
         | 
| 613 | 
            +
                      end
         | 
| 465 614 | 
             
                    else
         | 
| 466 | 
            -
                       | 
| 615 | 
            +
                      advance
         | 
| 467 616 | 
             
                    end
         | 
| 468 617 | 
             
                  end
         | 
| 469 618 |  | 
| 470 | 
            -
                  def  | 
| 471 | 
            -
                    if scanner.scan  | 
| 472 | 
            -
                      @tokens << [: | 
| 473 | 
            -
             | 
| 619 | 
            +
                  def tokenize_fieldset
         | 
| 620 | 
            +
                    if scanner.scan %r[\s*{]
         | 
| 621 | 
            +
                      @tokens << [:FIELDSET]
         | 
| 622 | 
            +
             | 
| 623 | 
            +
                      push_state :fieldset
         | 
| 474 624 | 
             
                    else
         | 
| 475 | 
            -
                       | 
| 625 | 
            +
                      raise LexerError, "Expecting `{` got `#{scanner.peek(3)}`"
         | 
| 476 626 | 
             
                    end
         | 
| 477 627 | 
             
                  end
         | 
| 478 628 |  | 
| @@ -497,6 +647,10 @@ module Graphlyte | |
| 497 647 | 
             
                  end
         | 
| 498 648 |  | 
| 499 649 | 
             
                  def advance
         | 
| 650 | 
            +
                    unless scanner.check /\s/
         | 
| 651 | 
            +
                      raise LexerError, "Unexpected Char: '#{scanner.peek(3)}'"
         | 
| 652 | 
            +
                    end
         | 
| 653 | 
            +
             | 
| 500 654 | 
             
                    scanner.pos = scanner.pos + 1
         | 
| 501 655 | 
             
                  end
         | 
| 502 656 |  | 
| @@ -1,12 +1,52 @@ | |
| 1 1 | 
             
            module Graphlyte
         | 
| 2 2 | 
             
              module Schema
         | 
| 3 3 | 
             
                module Types
         | 
| 4 | 
            +
                  class Defaults
         | 
| 5 | 
            +
                    attr_reader :value
         | 
| 6 | 
            +
                    def initialize(value)
         | 
| 7 | 
            +
                      @value = value
         | 
| 8 | 
            +
                    end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                    def merge!(str)
         | 
| 11 | 
            +
                      parse_value(@value, str)
         | 
| 12 | 
            +
                    end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                    def parse_value(value, str)
         | 
| 15 | 
            +
                      if value.is_a?(Hash)
         | 
| 16 | 
            +
                        str << "{ "
         | 
| 17 | 
            +
                        value.each_with_index do |(k, v), idx|
         | 
| 18 | 
            +
                          str << "#{k}: "
         | 
| 19 | 
            +
                          parse_value(v, str)
         | 
| 20 | 
            +
                          str << ", " if idx < (value.size - 1)
         | 
| 21 | 
            +
                        end
         | 
| 22 | 
            +
                        str << " }"
         | 
| 23 | 
            +
                      elsif value.is_a?(Array)
         | 
| 24 | 
            +
                        str << "["
         | 
| 25 | 
            +
                        value.each_with_index do |item, idx|
         | 
| 26 | 
            +
                          parse_value(item, str)
         | 
| 27 | 
            +
                          str << ", " if idx < (value.size - 1)
         | 
| 28 | 
            +
                        end
         | 
| 29 | 
            +
                        str << "]"
         | 
| 30 | 
            +
                      elsif value.is_a?(Symbol)
         | 
| 31 | 
            +
                        str << value.to_s
         | 
| 32 | 
            +
                      else
         | 
| 33 | 
            +
                        str << "#{Arguments::Value.new(value).to_s}"
         | 
| 34 | 
            +
                      end
         | 
| 35 | 
            +
                    end
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
             | 
| 4 38 | 
             
                  class Base
         | 
| 5 39 | 
             
                    attr_reader :name, :placeholder
         | 
| 6 40 |  | 
| 7 | 
            -
                    def initialize(name, placeholder)
         | 
| 41 | 
            +
                    def initialize(name, placeholder, defaults=nil)
         | 
| 8 42 | 
             
                      @name = name
         | 
| 9 43 | 
             
                      @placeholder = placeholder
         | 
| 44 | 
            +
                      @defaults = defaults
         | 
| 45 | 
            +
                    end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                    def default
         | 
| 48 | 
            +
                      return nil if @defaults.class == NilClass
         | 
| 49 | 
            +
                      Defaults.new(@defaults)
         | 
| 10 50 | 
             
                    end
         | 
| 11 51 | 
             
                  end
         | 
| 12 52 | 
             
                end
         | 
    
        data/lib/graphlyte/types.rb
    CHANGED
    
    | @@ -2,8 +2,8 @@ require_relative "schema/types/base" | |
| 2 2 |  | 
| 3 3 | 
             
            module Graphlyte
         | 
| 4 4 | 
             
              class Types
         | 
| 5 | 
            -
                def method_missing(method, placeholder)
         | 
| 6 | 
            -
                  Schema::Types::Base.new(method, placeholder)
         | 
| 5 | 
            +
                def method_missing(method, placeholder, default = nil)
         | 
| 6 | 
            +
                  Schema::Types::Base.new(method, placeholder, default)
         | 
| 7 7 | 
             
                end
         | 
| 8 8 | 
             
              end
         | 
| 9 9 | 
             
            end
         | 
    
        data/lib/graphlyte.rb
    CHANGED
    
    | @@ -2,13 +2,14 @@ require 'json' | |
| 2 2 | 
             
            require_relative "./graphlyte/fieldset"
         | 
| 3 3 | 
             
            require_relative "./graphlyte/query"
         | 
| 4 4 | 
             
            require_relative "./graphlyte/fragment"
         | 
| 5 | 
            +
            require_relative 'graphlyte/inline_fragment'
         | 
| 5 6 | 
             
            require_relative "./graphlyte/schema_query"
         | 
| 6 7 | 
             
            require_relative "./graphlyte/types"
         | 
| 7 8 | 
             
            require_relative "./graphlyte/schema/parser"
         | 
| 8 9 |  | 
| 9 10 | 
             
            module Graphlyte
         | 
| 10 11 | 
             
              extend SchemaQuery
         | 
| 11 | 
            -
             | 
| 12 | 
            +
             | 
| 12 13 | 
             
              TYPES = Types.new
         | 
| 13 14 |  | 
| 14 15 | 
             
              def self.parse(gql)
         | 
| @@ -23,6 +24,18 @@ module Graphlyte | |
| 23 24 | 
             
                Query.new(name, :mutation, builder: build(&block))
         | 
| 24 25 | 
             
              end
         | 
| 25 26 |  | 
| 27 | 
            +
              def self.custom(name, type, &block)
         | 
| 28 | 
            +
                Query.new(name, type.to_sym, builder: build(&block))
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
              def self.inline_fragment(model_name, &block)
         | 
| 32 | 
            +
                InlineFragment.new(model_name, builder: build(&block))
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
              def self.inline_directive(directive, **hargs, &block)
         | 
| 36 | 
            +
                InlineFragment.from_directive(directive, **hargs, builder: build(&block) )
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
             | 
| 26 39 | 
             
              def self.fragment(fragment_name, model_name, &block)
         | 
| 27 40 | 
             
                Fragment.new(fragment_name, model_name, builder: build(&block))
         | 
| 28 41 | 
             
              end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: graphlyte
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.3.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Sean Gregory
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date:  | 
| 11 | 
            +
            date: 2022-03-26 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: rspec
         | 
| @@ -48,9 +48,11 @@ files: | |
| 48 48 | 
             
            - lib/graphlyte/arguments/set.rb
         | 
| 49 49 | 
             
            - lib/graphlyte/arguments/value.rb
         | 
| 50 50 | 
             
            - lib/graphlyte/builder.rb
         | 
| 51 | 
            +
            - lib/graphlyte/directive.rb
         | 
| 51 52 | 
             
            - lib/graphlyte/field.rb
         | 
| 52 53 | 
             
            - lib/graphlyte/fieldset.rb
         | 
| 53 54 | 
             
            - lib/graphlyte/fragment.rb
         | 
| 55 | 
            +
            - lib/graphlyte/inline_fragment.rb
         | 
| 54 56 | 
             
            - lib/graphlyte/query.rb
         | 
| 55 57 | 
             
            - lib/graphlyte/refinements/string_refinement.rb
         | 
| 56 58 | 
             
            - lib/graphlyte/schema/parser.rb
         |