graphlyte 0.1.2 → 0.1.3
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.rb +13 -161
- data/lib/graphlyte/arguments/set.rb +46 -0
- data/lib/graphlyte/arguments/value.rb +19 -0
- data/lib/graphlyte/builder.rb +39 -0
- data/lib/graphlyte/field.rb +47 -0
- data/lib/graphlyte/fieldset.rb +36 -0
- data/lib/graphlyte/fragment.rb +17 -0
- data/lib/graphlyte/query.rb +48 -0
- metadata +8 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 82edd3a321164acd153524e98420c75175deb60d1fd56d28f72f52917e35dac4
|
4
|
+
data.tar.gz: '049a43943a6ba45edff3a73347c903be52f0d4e4d7e9f76a9be50e0e45ed11a6'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a1a81b6258e70829db7010ce3c2ca3cdd818dadd0cdc21878c6e10eaefd7baa54d816fd3810c92f330699d905ed5ad00f7865c169f0290e96f4290dbf5cf8160
|
7
|
+
data.tar.gz: b3bc5db253642508d0f9e93c7882525706fe7c9e1ec687e4b7f506a6096a9ba8ecb2a6e6cc1653318467911b70c01243a4bf9f55d7cd22ccf2618cfff912bfbd
|
data/lib/graphlyte.rb
CHANGED
@@ -1,174 +1,26 @@
|
|
1
1
|
require 'json'
|
2
|
+
require_relative "./graphlyte/fieldset"
|
3
|
+
require_relative "./graphlyte/query"
|
4
|
+
require_relative "./graphlyte/fragment"
|
5
|
+
|
2
6
|
module Graphlyte
|
3
7
|
def self.query(name = nil, &block)
|
4
|
-
|
5
|
-
block.call(query) if block
|
6
|
-
query
|
8
|
+
Query.new(name, builder: build(&block))
|
7
9
|
end
|
8
10
|
|
9
|
-
def self.fragment(fragment_name, model_name
|
10
|
-
|
11
|
-
block.call(fragment) if block
|
12
|
-
fragment
|
11
|
+
def self.fragment(fragment_name, model_name, &block)
|
12
|
+
Fragment.new(fragment_name, model_name, builder: build(&block))
|
13
13
|
end
|
14
14
|
|
15
15
|
def self.fieldset(model_name=nil, &block)
|
16
|
-
|
17
|
-
block.call(fieldset) if block
|
18
|
-
fieldset
|
19
|
-
end
|
20
|
-
|
21
|
-
module Buildable
|
22
|
-
def <<(buildable)
|
23
|
-
raise "Must pass a Fieldset or Fragment" unless [Fragment, Fieldset].include?(buildable.class)
|
24
|
-
@fields.concat(buildable._fields) if buildable.class.eql? Fieldset
|
25
|
-
@fields << buildable if buildable.class.eql? Fragment
|
26
|
-
end
|
27
|
-
|
28
|
-
def method_missing(method, optional_fieldset_or_args=nil, hargs={}, &block)
|
29
|
-
field = [Fieldset, Fragment].include?(optional_fieldset_or_args.class) ?
|
30
|
-
Field.new(method, optional_fieldset_or_args, hargs) :
|
31
|
-
Field.new(method, Fieldset.empty, optional_fieldset_or_args)
|
32
|
-
block.call(field.value) if block
|
33
|
-
@fields << field
|
34
|
-
field
|
35
|
-
end
|
16
|
+
Fieldset.new(model_name, builder: build(&block))
|
36
17
|
end
|
37
18
|
|
38
|
-
|
39
|
-
include Buildable
|
40
|
-
|
41
|
-
def self.empty
|
42
|
-
new
|
43
|
-
end
|
44
|
-
|
45
|
-
def initialize(model_name = nil)
|
46
|
-
@model_name = model_name
|
47
|
-
@fields = []
|
48
|
-
end
|
49
|
-
|
50
|
-
def _model_name
|
51
|
-
@model_name
|
52
|
-
end
|
53
|
-
|
54
|
-
def _fields
|
55
|
-
@fields
|
56
|
-
end
|
57
|
-
|
58
|
-
def empty?
|
59
|
-
@fields.empty?
|
60
|
-
end
|
61
|
-
|
62
|
-
def can_validate?
|
63
|
-
!@model_name.nil?
|
64
|
-
end
|
65
|
-
|
66
|
-
def to_s(indent=0)
|
67
|
-
@fields.map { |field| field.to_s(indent)}.join("\n")
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
class Query < Fieldset
|
72
|
-
|
73
|
-
def initialize(query_name=nil)
|
74
|
-
@query_name = query_name
|
75
|
-
@fields = []
|
76
|
-
end
|
77
|
-
|
78
|
-
def to_json
|
79
|
-
{ query: to_s }.to_json
|
80
|
-
end
|
81
|
-
|
82
|
-
def to_s(indent=0)
|
83
|
-
"{\n#{super(indent + 1)}\n}\n#{format_fragments}\n"
|
84
|
-
end
|
85
|
-
|
86
|
-
def format_fragments
|
87
|
-
str = ""
|
88
|
-
flatten(@fields).each do |_, fragment|
|
89
|
-
str += "\nfragment #{fragment.name}"
|
90
|
-
str += " on #{fragment._model_name}" unless fragment._model_name.nil?
|
91
|
-
str += " {\n#{fragment._fields.map {|f| f.to_s(1) }.join("\n")}\n}"
|
92
|
-
end
|
93
|
-
str
|
94
|
-
end
|
95
|
-
|
96
|
-
def flatten(fields=@fields, new_fields = {})
|
97
|
-
fields.each do |field|
|
98
|
-
if field.class.eql?(Fragment)
|
99
|
-
new_fields[field.name] = field
|
100
|
-
unless field._fields.empty?
|
101
|
-
flatten(field._fields, new_fields)
|
102
|
-
end
|
103
|
-
else
|
104
|
-
if field.value.class.eql?(Fragment)
|
105
|
-
new_fields[field.value.name] = field.value
|
106
|
-
flatten(field.value._fields, new_fields) unless field.value._fields.empty?
|
107
|
-
else
|
108
|
-
flatten(field.value._fields, new_fields) unless field.value._fields.empty?
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
112
|
-
new_fields
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
class Fragment < Fieldset
|
117
|
-
attr_reader :fragment_name, :name
|
118
|
-
|
119
|
-
def initialize(fragment_name, model_name=nil)
|
120
|
-
@fragment_name = fragment_name
|
121
|
-
@name = fragment_name
|
122
|
-
super(model_name)
|
123
|
-
end
|
124
|
-
|
125
|
-
def to_s(indent=0)
|
126
|
-
actual_indent = ("\s" * indent) * 2
|
127
|
-
"#{actual_indent}...#{@fragment_name}#{actual_indent}"
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
class FieldArguments
|
132
|
-
def initialize(data)
|
133
|
-
@data = data
|
134
|
-
end
|
135
|
-
|
136
|
-
def to_s
|
137
|
-
return @data && !@data.empty? ? "(#{@data.map{|k, v| "#{k}: \"#{v}\""}.join(", ")})" : ""
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
class Field
|
142
|
-
attr_reader :name, :value, :inputs, :alias
|
143
|
-
|
144
|
-
def initialize(name, value=nil, hargs)
|
145
|
-
@name = name
|
146
|
-
@value = value
|
147
|
-
@inputs = FieldArguments.new(hargs)
|
148
|
-
@alias = nil
|
149
|
-
end
|
150
|
-
|
151
|
-
def atomic?
|
152
|
-
value.empty?
|
153
|
-
end
|
154
|
-
|
155
|
-
def alias(name, &block)
|
156
|
-
@alias = name
|
157
|
-
block.call(value) if block
|
158
|
-
end
|
19
|
+
private
|
159
20
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
str += "#{actual_indent}#{@alias}: #{name}"
|
165
|
-
str += inputs.to_s.empty? ? "()" : inputs.to_s
|
166
|
-
str += " "
|
167
|
-
else
|
168
|
-
str += "#{actual_indent}#{name}#{inputs.to_s}"
|
169
|
-
end
|
170
|
-
str += "{\n#{value.to_s(indent + 1)}#{actual_indent}\n#{actual_indent}}" unless atomic?
|
171
|
-
str
|
172
|
-
end
|
21
|
+
def self.build(&block)
|
22
|
+
builder = Builder.new
|
23
|
+
block.call(builder) if block
|
24
|
+
builder
|
173
25
|
end
|
174
26
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require_relative "./value"
|
2
|
+
module Graphlyte
|
3
|
+
module Arguments
|
4
|
+
class Set
|
5
|
+
|
6
|
+
attr_reader :values
|
7
|
+
|
8
|
+
def initialize(data)
|
9
|
+
raise ArgumentError, "input #{data} must be a hash" unless data.nil? || data.is_a?(Hash)
|
10
|
+
@values = expand_arguments(data) unless data.nil?
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s(inner = false)
|
14
|
+
return "" unless values && !values.empty?
|
15
|
+
arr = values.map do |k,v|
|
16
|
+
if v.is_a?(Array)
|
17
|
+
"#{k}: [#{v.map(&:to_s).join(", ")}]"
|
18
|
+
elsif v.is_a?(Set)
|
19
|
+
"#{k}: { #{v.to_s(true)} }"
|
20
|
+
else
|
21
|
+
"#{k}: #{v.to_s}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
return arr.join(", ") if inner
|
25
|
+
"(#{arr.join(", ")})"
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def expand_arguments(data)
|
31
|
+
data.inject({}) do |memo, (k, v)|
|
32
|
+
if v.is_a?(Array)
|
33
|
+
memo[k] = v.map do |item|
|
34
|
+
Value.new(item)
|
35
|
+
end
|
36
|
+
elsif v.is_a?(Hash)
|
37
|
+
memo[k] = Set.new(v)
|
38
|
+
else
|
39
|
+
memo[k] = Value.new(v)
|
40
|
+
end
|
41
|
+
memo
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Graphlyte
|
2
|
+
module Arguments
|
3
|
+
class Value
|
4
|
+
attr_reader :value
|
5
|
+
|
6
|
+
def initialize(value)
|
7
|
+
raise ArgumentError, "Hash not allowed in this context" if value.is_a? Hash
|
8
|
+
@value = value
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_s
|
12
|
+
return value if value.is_a? Numeric
|
13
|
+
return "\"#{value}\"" if value.is_a? String
|
14
|
+
return "null" if value.nil?
|
15
|
+
value.to_s
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require_relative "./field"
|
2
|
+
require_relative "./fieldset"
|
3
|
+
|
4
|
+
module Graphlyte
|
5
|
+
class Builder
|
6
|
+
def initialize
|
7
|
+
@fields = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def <<(buildable)
|
11
|
+
raise "Must pass a Fieldset or Fragment" unless [Fragment, Fieldset].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 buildable.class.eql? Fragment
|
17
|
+
end
|
18
|
+
|
19
|
+
def method_missing(method, fieldset_or_hargs=nil, hargs={}, &block)
|
20
|
+
# todo: camel case method
|
21
|
+
|
22
|
+
# hack for ruby bug in lower versions
|
23
|
+
if [Fieldset, Fragment].include?(fieldset_or_hargs.class)
|
24
|
+
field = Field.new(method, fieldset_or_hargs, hargs)
|
25
|
+
else
|
26
|
+
field = Field.new(method, Fieldset.empty, fieldset_or_hargs)
|
27
|
+
end
|
28
|
+
|
29
|
+
block.call(field.fieldset.builder) if block
|
30
|
+
@fields << field
|
31
|
+
field
|
32
|
+
end
|
33
|
+
|
34
|
+
# for internal use only
|
35
|
+
def >>
|
36
|
+
@fields
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require_relative "./arguments/set"
|
2
|
+
|
3
|
+
module Graphlyte
|
4
|
+
class Field
|
5
|
+
attr_reader :name, :fieldset, :inputs, :alias
|
6
|
+
|
7
|
+
def initialize(name, fieldset, hargs, inputs: Arguments::Set.new(hargs))
|
8
|
+
@name = to_camel_case(name.to_s)
|
9
|
+
@fieldset = fieldset
|
10
|
+
@inputs = inputs
|
11
|
+
@alias = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def atomic?
|
15
|
+
fieldset.empty?
|
16
|
+
end
|
17
|
+
|
18
|
+
def alias(name, &block)
|
19
|
+
@alias = name
|
20
|
+
block.call(fieldset.builder) if block
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_s(indent=0)
|
24
|
+
str = ""
|
25
|
+
actual_indent = ("\s" * indent) * 2
|
26
|
+
if @alias
|
27
|
+
str += "#{actual_indent}#{@alias}: #{name}"
|
28
|
+
str += inputs.to_s.empty? ? "()" : inputs.to_s
|
29
|
+
else
|
30
|
+
str += "#{actual_indent}#{name}#{inputs.to_s}"
|
31
|
+
end
|
32
|
+
str += " {\n#{fieldset.to_s(indent + 1)}\n#{actual_indent}}" unless atomic?
|
33
|
+
str
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_camel_case(string)
|
37
|
+
start_of_string = string.match(/(^_+)/)&.[](0)
|
38
|
+
end_of_string = string.match(/(_+$)/)&.[](0)
|
39
|
+
|
40
|
+
middle = string.split("_").reject(&:empty?).inject([]) do |memo, str|
|
41
|
+
memo << (memo.empty? ? str : str.capitalize)
|
42
|
+
end.join("")
|
43
|
+
|
44
|
+
"#{start_of_string}#{middle}#{end_of_string}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,36 @@
|
|
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
|
@@ -0,0 +1,17 @@
|
|
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
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Graphlyte
|
2
|
+
class Query < Fieldset
|
3
|
+
|
4
|
+
attr_reader :name
|
5
|
+
|
6
|
+
def initialize(query_name=nil, **hargs)
|
7
|
+
@name = query_name
|
8
|
+
super(**hargs)
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_json
|
12
|
+
{ query: to_s }.to_json
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s(indent=0)
|
16
|
+
"{\n#{super(indent + 1)}\n}#{format_fragments}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def format_fragments
|
20
|
+
str = "\n"
|
21
|
+
flatten(builder.>>).each do |_, fragment|
|
22
|
+
str += "\nfragment #{fragment.fragment}"
|
23
|
+
str += " on #{fragment.model_name}" unless fragment.model_name.nil?
|
24
|
+
str += " {\n#{fragment.fields.map {|f| f.to_s(1) }.join("\n")}\n}"
|
25
|
+
end
|
26
|
+
str
|
27
|
+
end
|
28
|
+
|
29
|
+
def flatten(fields, new_fields = {})
|
30
|
+
fields.each do |field|
|
31
|
+
if field.class.eql?(Fragment)
|
32
|
+
new_fields[field.fragment] = field
|
33
|
+
unless field.empty?
|
34
|
+
flatten(field.fields, new_fields)
|
35
|
+
end
|
36
|
+
else
|
37
|
+
if field.fieldset.class.eql?(Fragment)
|
38
|
+
new_fields[field.fieldset.fragment] = field.fieldset
|
39
|
+
flatten(field.fieldset.fields, new_fields) unless field.atomic?
|
40
|
+
else
|
41
|
+
flatten(field.fieldset.fields, new_fields) unless field.atomic?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
new_fields
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphlyte
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sean Gregory
|
@@ -45,6 +45,13 @@ extensions: []
|
|
45
45
|
extra_rdoc_files: []
|
46
46
|
files:
|
47
47
|
- lib/graphlyte.rb
|
48
|
+
- lib/graphlyte/arguments/set.rb
|
49
|
+
- lib/graphlyte/arguments/value.rb
|
50
|
+
- lib/graphlyte/builder.rb
|
51
|
+
- lib/graphlyte/field.rb
|
52
|
+
- lib/graphlyte/fieldset.rb
|
53
|
+
- lib/graphlyte/fragment.rb
|
54
|
+
- lib/graphlyte/query.rb
|
48
55
|
homepage: https://rubygems.org/gems/graphlyte
|
49
56
|
licenses:
|
50
57
|
- MIT
|