graphlyte 0.3.2 → 1.0.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/data.rb +68 -0
- data/lib/graphlyte/document.rb +131 -0
- data/lib/graphlyte/dsl.rb +86 -0
- data/lib/graphlyte/editor.rb +288 -0
- data/lib/graphlyte/editors/annotate_types.rb +75 -0
- data/lib/graphlyte/editors/canonicalize.rb +26 -0
- data/lib/graphlyte/editors/collect_variable_references.rb +36 -0
- data/lib/graphlyte/editors/infer_signature.rb +36 -0
- data/lib/graphlyte/editors/inline_fragments.rb +37 -0
- data/lib/graphlyte/editors/remove_unneeded_spreads.rb +64 -0
- data/lib/graphlyte/editors/select_operation.rb +116 -0
- data/lib/graphlyte/editors/with_variables.rb +106 -0
- data/lib/graphlyte/errors.rb +33 -0
- data/lib/graphlyte/lexer.rb +392 -0
- data/lib/graphlyte/lexing/location.rb +43 -0
- data/lib/graphlyte/lexing/token.rb +31 -0
- data/lib/graphlyte/parser.rb +269 -0
- data/lib/graphlyte/parsing/backtracking_parser.rb +160 -0
- data/lib/graphlyte/refinements/string_refinement.rb +14 -8
- data/lib/graphlyte/refinements/syntax_refinements.rb +62 -0
- data/lib/graphlyte/schema.rb +165 -0
- data/lib/graphlyte/schema_query.rb +82 -65
- data/lib/graphlyte/selection_builder.rb +189 -0
- data/lib/graphlyte/selector.rb +75 -0
- data/lib/graphlyte/serializer.rb +223 -0
- data/lib/graphlyte/syntax.rb +369 -0
- data/lib/graphlyte.rb +24 -42
- metadata +88 -19
- data/lib/graphlyte/arguments/set.rb +0 -94
- data/lib/graphlyte/arguments/value.rb +0 -42
- data/lib/graphlyte/arguments/value_literal.rb +0 -17
- data/lib/graphlyte/builder.rb +0 -59
- data/lib/graphlyte/directive.rb +0 -25
- data/lib/graphlyte/field.rb +0 -65
- data/lib/graphlyte/fieldset.rb +0 -36
- data/lib/graphlyte/fragment.rb +0 -17
- data/lib/graphlyte/inline_fragment.rb +0 -29
- data/lib/graphlyte/query.rb +0 -150
- data/lib/graphlyte/schema/parser.rb +0 -687
- data/lib/graphlyte/schema/types/base.rb +0 -54
- data/lib/graphlyte/types.rb +0 -9
@@ -1,42 +0,0 @@
|
|
1
|
-
require_relative "./../refinements/string_refinement"
|
2
|
-
module Graphlyte
|
3
|
-
module Arguments
|
4
|
-
class Value
|
5
|
-
using Refinements::StringRefinement
|
6
|
-
|
7
|
-
attr_reader :value
|
8
|
-
|
9
|
-
def initialize(value)
|
10
|
-
raise ArgumentError, "Hash not allowed in this context" if value.is_a? Hash
|
11
|
-
@value = value
|
12
|
-
end
|
13
|
-
|
14
|
-
def self.from(value)
|
15
|
-
return value if value.is_a? self
|
16
|
-
|
17
|
-
new(value)
|
18
|
-
end
|
19
|
-
|
20
|
-
def symbol?
|
21
|
-
value.is_a? Symbol
|
22
|
-
end
|
23
|
-
|
24
|
-
def formal?
|
25
|
-
value.is_a? Schema::Types::Base
|
26
|
-
end
|
27
|
-
|
28
|
-
def refresh(args)
|
29
|
-
@value = value.call(args) if value.is_a? Proc
|
30
|
-
end
|
31
|
-
|
32
|
-
def to_s(raw = false)
|
33
|
-
return "$#{value.to_s.to_camel_case}" if value.is_a? Symbol
|
34
|
-
return value if value.is_a? Numeric
|
35
|
-
return "\"#{value}\"" if value.is_a?(String) && !raw
|
36
|
-
return "null" if value.nil?
|
37
|
-
return "$#{value.placeholder.to_camel_case}" if value.is_a? Schema::Types::Base
|
38
|
-
value.to_s
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
module Graphlyte
|
2
|
-
module Arguments
|
3
|
-
class ValueLiteral
|
4
|
-
attr_reader :value
|
5
|
-
|
6
|
-
def initialize(string)
|
7
|
-
raise 'Value must be a string' unless string.class == String
|
8
|
-
|
9
|
-
@value = string
|
10
|
-
end
|
11
|
-
|
12
|
-
def to_s
|
13
|
-
@value
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
data/lib/graphlyte/builder.rb
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
require_relative "./field"
|
2
|
-
require_relative "./fieldset"
|
3
|
-
|
4
|
-
module Graphlyte
|
5
|
-
class Builder
|
6
|
-
def initialize(fields = [])
|
7
|
-
@fields = fields
|
8
|
-
end
|
9
|
-
|
10
|
-
def <<(buildable)
|
11
|
-
raise "Must pass a Fieldset or Fragment" unless [Fragment, Fieldset, InlineFragment].include?(buildable.class)
|
12
|
-
|
13
|
-
@fields.concat(buildable.fields) if buildable.class.eql? Fieldset
|
14
|
-
|
15
|
-
# todo: handle fragments better, it's not a field
|
16
|
-
@fields << buildable if [InlineFragment, Fragment].include? buildable.class
|
17
|
-
end
|
18
|
-
|
19
|
-
def remove(field_symbol)
|
20
|
-
@fields.reject! do |field|
|
21
|
-
field.class == Fragment ? false : field.name == field_symbol.to_s
|
22
|
-
end
|
23
|
-
|
24
|
-
@fields.select { |field| field.class == Fragment }.each do |fragment|
|
25
|
-
fragment.fields.reject! do |field|
|
26
|
-
field.name == field_symbol.to_s
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def method_missing(method, fieldset_or_hargs=nil, hargs={}, &block)
|
32
|
-
# todo: camel case method
|
33
|
-
|
34
|
-
# hack for ruby bug in lower versions
|
35
|
-
if [Fieldset, Fragment, InlineFragment].include?(fieldset_or_hargs.class)
|
36
|
-
field = Field.new(method, fieldset_or_hargs, hargs)
|
37
|
-
else
|
38
|
-
field = Field.new(method, Fieldset.empty, fieldset_or_hargs)
|
39
|
-
end
|
40
|
-
|
41
|
-
field.fieldset.builder.>.instance_eval(&block) if block
|
42
|
-
@fields << field
|
43
|
-
field
|
44
|
-
end
|
45
|
-
|
46
|
-
def respond_to_missing
|
47
|
-
true
|
48
|
-
end
|
49
|
-
|
50
|
-
# for internal use only
|
51
|
-
def >>
|
52
|
-
@fields
|
53
|
-
end
|
54
|
-
|
55
|
-
def >
|
56
|
-
self
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
data/lib/graphlyte/directive.rb
DELETED
@@ -1,25 +0,0 @@
|
|
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, args: nil)
|
13
|
-
# add directive after fieldname?
|
14
|
-
string += ' ' * indent unless indent.nil?
|
15
|
-
if !args.nil? && args.to_s.empty?
|
16
|
-
string += "#{field} " if field
|
17
|
-
else
|
18
|
-
string += "#{field}#{args.to_s} "
|
19
|
-
end
|
20
|
-
string += "@#{name}"
|
21
|
-
string += @inputs.to_s unless @inputs.to_s.empty?
|
22
|
-
string
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
data/lib/graphlyte/field.rb
DELETED
@@ -1,65 +0,0 @@
|
|
1
|
-
require_relative "./arguments/set"
|
2
|
-
require_relative 'directive'
|
3
|
-
require_relative "./refinements/string_refinement"
|
4
|
-
module Graphlyte
|
5
|
-
class Field
|
6
|
-
using Refinements::StringRefinement
|
7
|
-
|
8
|
-
attr_reader :name, :fieldset, :inputs, :directive
|
9
|
-
|
10
|
-
def initialize(name, fieldset, hargs, directive: nil, inputs: Arguments::Set.new(hargs))
|
11
|
-
@name = name.to_s.to_camel_case
|
12
|
-
@fieldset = fieldset
|
13
|
-
@inputs = inputs
|
14
|
-
@alias = nil
|
15
|
-
@directive = directive
|
16
|
-
end
|
17
|
-
|
18
|
-
def atomic?
|
19
|
-
fieldset.empty?
|
20
|
-
end
|
21
|
-
|
22
|
-
def alias(name, &block)
|
23
|
-
@alias = name
|
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)
|
37
|
-
end
|
38
|
-
|
39
|
-
def to_s(indent=0)
|
40
|
-
str = ""
|
41
|
-
actual_indent = ("\s" * indent) * 2
|
42
|
-
if @alias
|
43
|
-
str += "#{actual_indent}#{@alias}: #{name}"
|
44
|
-
str += inputs.to_s.empty? ? "()" : inputs.to_s
|
45
|
-
elsif @directive
|
46
|
-
str = @directive.inflate(indent * 2, str, field: name, args: inputs)
|
47
|
-
else
|
48
|
-
str += "#{actual_indent}#{name}#{inputs.to_s}"
|
49
|
-
end
|
50
|
-
str += " {\n#{fieldset.to_s(indent + 1)}\n#{actual_indent}}" unless atomic?
|
51
|
-
str
|
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
|
64
|
-
end
|
65
|
-
end
|
data/lib/graphlyte/fieldset.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
require_relative "./builder"
|
2
|
-
|
3
|
-
module Graphlyte
|
4
|
-
class Fieldset
|
5
|
-
def self.empty
|
6
|
-
new
|
7
|
-
end
|
8
|
-
|
9
|
-
attr_reader :model_name, :builder
|
10
|
-
|
11
|
-
def initialize(model_name = nil, builder: Builder.new)
|
12
|
-
@model_name = model_name
|
13
|
-
@builder = builder
|
14
|
-
end
|
15
|
-
|
16
|
-
def fields
|
17
|
-
builder.>>
|
18
|
-
end
|
19
|
-
|
20
|
-
def empty?
|
21
|
-
fields.empty?
|
22
|
-
end
|
23
|
-
|
24
|
-
def to_s(indent=0)
|
25
|
-
fields.map { |field| field.to_s(indent) }.join("\n")
|
26
|
-
end
|
27
|
-
|
28
|
-
def to_a
|
29
|
-
[ to_s ]
|
30
|
-
end
|
31
|
-
|
32
|
-
def +(fieldset)
|
33
|
-
to_s + "\n" + fieldset.to_s
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
data/lib/graphlyte/fragment.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
require_relative "./fieldset"
|
2
|
-
|
3
|
-
module Graphlyte
|
4
|
-
class Fragment < Fieldset
|
5
|
-
attr_reader :fragment
|
6
|
-
|
7
|
-
def initialize(fragment_name, model_name=nil, **hargs)
|
8
|
-
@fragment = fragment_name
|
9
|
-
super(model_name, **hargs)
|
10
|
-
end
|
11
|
-
|
12
|
-
def to_s(indent=0)
|
13
|
-
actual_indent = ("\s" * indent) * 2
|
14
|
-
"#{actual_indent}...#{fragment}#{actual_indent}"
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,29 +0,0 @@
|
|
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(0, 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
DELETED
@@ -1,150 +0,0 @@
|
|
1
|
-
require_relative "./refinements/string_refinement"
|
2
|
-
require "json"
|
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
|
-
next if field.class == Fragment
|
15
|
-
|
16
|
-
modify(field.fieldset.fields, [token], &block)
|
17
|
-
field.fieldset.builder.instance_eval(&block) unless field.fieldset.fields.empty?
|
18
|
-
end
|
19
|
-
else
|
20
|
-
needle = fields.find do |field|
|
21
|
-
field.name == token
|
22
|
-
end
|
23
|
-
|
24
|
-
raise "#{token} not found in query" unless needle
|
25
|
-
|
26
|
-
if selector_tokens.size.zero?
|
27
|
-
needle.fieldset.builder.instance_eval(&block)
|
28
|
-
else
|
29
|
-
modify(needle.fieldset.fields, selector_tokens, &block)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
class Query < Fieldset
|
36
|
-
using Refinements::StringRefinement
|
37
|
-
attr_reader :name, :type
|
38
|
-
|
39
|
-
def initialize(query_name=nil, type=:query, **hargs)
|
40
|
-
@name = query_name || "anonymousQuery"
|
41
|
-
@type = type
|
42
|
-
super(**hargs)
|
43
|
-
end
|
44
|
-
|
45
|
-
def at(selector, &block)
|
46
|
-
Selector.new(selector).modify(fields, &block)
|
47
|
-
end
|
48
|
-
|
49
|
-
def placeholders
|
50
|
-
flatten_variables(builder.>>).map do |value|
|
51
|
-
unless value.formal?
|
52
|
-
str = ":#{value.value.to_sym.inspect} of unknown"
|
53
|
-
else
|
54
|
-
str = ":#{value.value.placeholder} of #{value.value.name}"
|
55
|
-
end
|
56
|
-
|
57
|
-
if value.value.default
|
58
|
-
str += " with default "
|
59
|
-
value.value.default.merge!(str)
|
60
|
-
end
|
61
|
-
str
|
62
|
-
end.join("\n")
|
63
|
-
end
|
64
|
-
|
65
|
-
def to_json(query_name=name, **hargs)
|
66
|
-
variables = flatten_variables(builder.>>).uniq { |v| v.value }
|
67
|
-
types = merge_variable_types(variables, hargs)
|
68
|
-
|
69
|
-
str = "#{type} #{query_name}"
|
70
|
-
unless types.empty?
|
71
|
-
type_new = types.map do |type_arr|
|
72
|
-
type_str = "$#{type_arr[0].to_camel_case}: #{type_arr[1]}"
|
73
|
-
unless type_arr[2].nil?
|
74
|
-
type_str << " = "
|
75
|
-
type_arr[2].merge!(type_str)
|
76
|
-
end
|
77
|
-
type_str
|
78
|
-
end
|
79
|
-
str += "(#{type_new.join(", ")})"
|
80
|
-
end
|
81
|
-
{ query: "#{str} #{to_s(1)}", variables: Arguments::Set.new(hargs).to_h(true) }.to_json
|
82
|
-
end
|
83
|
-
|
84
|
-
def to_s(indent=0)
|
85
|
-
"{\n#{super(indent + 1)}\n}#{format_fragments}"
|
86
|
-
end
|
87
|
-
|
88
|
-
def merge_variable_types(variables=[], hargs)
|
89
|
-
variables.inject([]) do |memo, var|
|
90
|
-
unless var.formal?
|
91
|
-
if hargs[var.value].is_a? String
|
92
|
-
memo << [var.value.to_camel_case, "String"]
|
93
|
-
elsif [TrueClass, FalseClass].include? hargs[var.value].class
|
94
|
-
memo << [var.value ,"Boolean"]
|
95
|
-
elsif hargs[var.value].is_a? Float
|
96
|
-
memo << [var.value, "Float"]
|
97
|
-
elsif hargs[var.value].is_a? Integer
|
98
|
-
memo << [var.value, "Int"]
|
99
|
-
elsif hargs[var.value].is_a? Array
|
100
|
-
memo << "[#{merge_variable_types(var.value, hargs).first}]"
|
101
|
-
end
|
102
|
-
else
|
103
|
-
memo << [var.value.placeholder, var.value.name, var.value.default]
|
104
|
-
end
|
105
|
-
memo
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
def format_fragments
|
110
|
-
str = "\n"
|
111
|
-
flatten(builder.>>).each do |_, fragment|
|
112
|
-
str += "\nfragment #{fragment.fragment}"
|
113
|
-
str += " on #{fragment.model_name}" unless fragment.model_name.nil?
|
114
|
-
str += " {\n#{fragment.fields.map {|f| f.to_s(1) }.join("\n")}\n}"
|
115
|
-
end
|
116
|
-
str
|
117
|
-
end
|
118
|
-
|
119
|
-
def flatten_variables(fields, variables=[])
|
120
|
-
fields.each do |field|
|
121
|
-
variables.concat field.inputs.extract_variables unless [InlineFragment, Fragment].include? field.class
|
122
|
-
variables.concat field.directive.inputs.extract_variables if field.respond_to?(:directive) && field.directive
|
123
|
-
if [InlineFragment, Fragment].include? field.class
|
124
|
-
flatten_variables(field.fields, variables)
|
125
|
-
else
|
126
|
-
flatten_variables(field.fieldset.fields, variables)
|
127
|
-
end
|
128
|
-
end
|
129
|
-
variables
|
130
|
-
end
|
131
|
-
|
132
|
-
def flatten(fields, new_fields = {})
|
133
|
-
fields.each do |field|
|
134
|
-
next if field.class == InlineFragment
|
135
|
-
if field.class.eql?(Fragment)
|
136
|
-
new_fields[field.fragment] = field
|
137
|
-
unless field.empty?
|
138
|
-
flatten(field.fields, new_fields)
|
139
|
-
end
|
140
|
-
else
|
141
|
-
if field.fieldset.class.eql?(Fragment)
|
142
|
-
new_fields[field.fieldset.fragment] = field.fieldset
|
143
|
-
end
|
144
|
-
flatten(field.fieldset.fields, new_fields) unless field.atomic?
|
145
|
-
end
|
146
|
-
end
|
147
|
-
new_fields
|
148
|
-
end
|
149
|
-
end
|
150
|
-
end
|