gql 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e3b82548839c3920e499f9256cab69aa5ba31081
4
- data.tar.gz: c1631dc4bac082ad2086eadbe816791971f45b57
3
+ metadata.gz: c2a09930fd0d6998f3652bd99bacce706c64fb0e
4
+ data.tar.gz: 0d8a5d883919be233726b729ed4a7bec89c5958f
5
5
  SHA512:
6
- metadata.gz: 71d53e0856f5c0937d980deb1e1f27351dd9f76c84a6a9f449d23a26483bfd2745323c5d39fde5a480783f052389daf9ee5f690fc071f3eabc3bed3ebe308f8b
7
- data.tar.gz: 0247f336c99c7365ebe800e1df5213cbdc9d525d1f4cf9ceb44b689b60547fe99a7126a9ed7ebc59400b6264a6af0397a505808f8ee8f2e03e31de3300f15c20
6
+ metadata.gz: bf6337d65cc3a325006f1c0f87c932ae3344b035776e9a3d698deffc00421c88714d13009b8659ab2dee75e524d089966edede001ed68b49c0c17e968ece9a8d
7
+ data.tar.gz: 926bdde87803db064e8f4f9cb6834e4d2181a0bf1cea895a8f2d244140313140e63b3b479ce46a6f424a44cac34bad7548d2e13ded7245acbf3957bcc00b0e74
data/README.md CHANGED
@@ -33,7 +33,7 @@ TODO: Write usage instructions here
33
33
 
34
34
  ## Example
35
35
 
36
- Run `bin/console` for an interactive prompt and enter the following:
36
+ Run `bin/console` for an interactive prompt (loaded with example models/data) and enter the following:
37
37
 
38
38
  ```ruby
39
39
  puts q(<<-QUERY_STRING).to_json
@@ -78,69 +78,69 @@ QUERY_STRING
78
78
  This should result in the following JSON (after prettyfication):
79
79
 
80
80
  ```json
81
- {
82
- "id": "ma",
83
- "is_admin": true,
84
- "name": "Martin Andert",
85
- "created_year_and_month": {
86
- "year": 2010,
87
- "month": 3
88
- },
89
- "created": "March 04, 2010 14:04",
90
- "account": {
91
- "bank_name": "Foo Bank",
92
- "iban": "987654321",
93
- "saldo_string": "100000.00 EUR",
94
- "saldo": {
95
- "currency": "EUR",
96
- "cents": 10000000
97
- }
98
- },
99
- "albums": {
100
- "count": 2,
101
- "edges": [
102
- {
103
- "cursor": "1",
104
- "node": {
105
- "artist": "Metallica",
106
- "title": "Black Album",
107
- "songs": {
108
- "edges": [
109
- {
110
- "id": 1,
111
- "upcased_title": "ENTER SANDMAN",
112
- "upcased_title_length": 13
113
- }, {
114
- "id": 2,
115
- "upcased_title": "SAD BUT TRUE",
116
- "upcased_title_length": 12
117
- }
118
- ]
119
- }
81
+ {
82
+ "id": "ma",
83
+ "is_admin": true,
84
+ "name": "Martin Andert",
85
+ "created_year_and_month": {
86
+ "year": 2010,
87
+ "month": 3
88
+ },
89
+ "created": "March 04, 2010 14:04",
90
+ "account": {
91
+ "bank_name": "Foo Bank",
92
+ "iban": "987654321",
93
+ "saldo_string": "100000.00 EUR",
94
+ "saldo": {
95
+ "currency": "EUR",
96
+ "cents": 10000000
97
+ }
98
+ },
99
+ "albums": {
100
+ "count": 2,
101
+ "edges": [
102
+ {
103
+ "cursor": "1",
104
+ "node": {
105
+ "artist": "Metallica",
106
+ "title": "Black Album",
107
+ "songs": {
108
+ "edges": [
109
+ {
110
+ "id": 1,
111
+ "upcased_title": "ENTER SANDMAN",
112
+ "upcased_title_length": 13
113
+ }, {
114
+ "id": 2,
115
+ "upcased_title": "SAD BUT TRUE",
116
+ "upcased_title_length": 12
117
+ }
118
+ ]
120
119
  }
121
- }, {
122
- "cursor": "2",
123
- "node": {
124
- "artist": "Nirvana",
125
- "title": "Nevermind",
126
- "songs": {
127
- "edges": [
128
- {
129
- "id": 5,
130
- "upcased_title": "SMELLS LIKE TEEN SPIRIT",
131
- "upcased_title_length": 23
132
- }, {
133
- "id": 6,
134
- "upcased_title": "COME AS YOU ARE",
135
- "upcased_title_length": 15
136
- }
137
- ]
138
- }
120
+ }
121
+ }, {
122
+ "cursor": "2",
123
+ "node": {
124
+ "artist": "Nirvana",
125
+ "title": "Nevermind",
126
+ "songs": {
127
+ "edges": [
128
+ {
129
+ "id": 5,
130
+ "upcased_title": "SMELLS LIKE TEEN SPIRIT",
131
+ "upcased_title_length": 23
132
+ }, {
133
+ "id": 6,
134
+ "upcased_title": "COME AS YOU ARE",
135
+ "upcased_title_length": 15
136
+ }
137
+ ]
139
138
  }
140
139
  }
141
- ]
142
- }
140
+ }
141
+ ]
143
142
  }
143
+ }
144
144
  ```
145
145
 
146
146
 
data/lib/gql/call.rb CHANGED
@@ -1,6 +1,44 @@
1
1
  module GQL
2
2
  class Call
3
- attr_reader :target, :context
3
+ class Method
4
+ attr_reader :target, :context
5
+
6
+ def initialize(target, context)
7
+ @target, @context = target, context
8
+ end
9
+
10
+ def execute(method, args)
11
+ instance_exec(*args, &method)
12
+ end
13
+ end
14
+
15
+ class_attribute :method, :result_class, instance_accessor: false, instance_predicate: false
16
+
17
+ class << self
18
+ def build_class(result_class, method)
19
+ if result_class.is_a? Array
20
+ result_class.unshift Connection if result_class.size == 1
21
+ result_class.unshift Fields::Connection if result_class.size == 2
22
+
23
+ field_type_class, connection_class, node_class = result_class
24
+
25
+ unless field_type_class <= Fields::Connection
26
+ raise Errors::InvalidNodeClass.new(field_type_class, Fields::Connection)
27
+ end
28
+
29
+ result_class = field_type_class.build_class(nil, connection_class, node_class)
30
+ elsif result_class && !(result_class <= Node)
31
+ raise Errors::InvalidNodeClass.new(result_class, Node)
32
+ end
33
+
34
+ Class.new(self).tap do |call_class|
35
+ call_class.method = method
36
+ call_class.result_class = result_class
37
+ end
38
+ end
39
+ end
40
+
41
+ attr_reader :caller, :ast_node, :target, :variables, :context
4
42
 
5
43
  def initialize(caller, ast_node, target, variables, context)
6
44
  @caller, @ast_node, @target = caller, ast_node, target
@@ -8,18 +46,19 @@ module GQL
8
46
  end
9
47
 
10
48
  def execute
11
- args = substitute_variables(@ast_node.arguments)
12
- target = instance_exec(*args, &self.class.const_get(:Function))
49
+ args = substitute_variables(ast_node.arguments)
13
50
 
14
- result_class = self.class.const_get(:Result) || @caller.class
51
+ method = Method.new(target, context)
52
+ target = method.execute(self.class.method, args)
53
+ result_class = self.class.result_class || caller.class
15
54
 
16
- result = result_class.new(@ast_node, target, @variables, context)
17
- result.__value
55
+ result = result_class.new(ast_node, target, variables, context)
56
+ result.value
18
57
  end
19
58
 
20
59
  private
21
60
  def substitute_variables(args)
22
- args.map { |arg| arg.is_a?(Symbol) ? @variables[arg] : arg }
61
+ args.map { |arg| arg.is_a?(Symbol) ? variables[arg] : arg }
23
62
  end
24
63
  end
25
64
  end
data/lib/gql/config.rb ADDED
@@ -0,0 +1,23 @@
1
+ module GQL
2
+ class Config
3
+ def root_node_class
4
+ @@root_node_class ||= nil
5
+ end
6
+
7
+ def root_node_class=(value)
8
+ unless value.nil? || value <= Node
9
+ raise Errors::InvalidNodeClass.new(value, Node)
10
+ end
11
+
12
+ @@root_node_class = value
13
+ end
14
+
15
+ def field_types
16
+ @@field_types ||= {}
17
+ end
18
+
19
+ def field_types=(value)
20
+ @@field_types = value
21
+ end
22
+ end
23
+ end
@@ -1,35 +1,35 @@
1
+ require 'active_support/core_ext/class/attribute'
2
+
1
3
  module GQL
2
4
  class Connection < Node
3
- field :edges
4
-
5
- def initialize(node_class, *args)
6
- super(*args)
7
-
8
- @node_class = node_class
9
- end
5
+ class_attribute :node_class, instance_accessor: false, instance_predicate: false
10
6
 
11
- alias :items :__target
7
+ class << self
8
+ def build_class(node_class)
9
+ node_class ||= self.node_class
12
10
 
13
- def edges_ast_node
14
- @edges_ast_node ||= @ast_node.fields.find { |f| f.name == :edges }
15
- end
11
+ if node_class.nil?
12
+ raise Errors::UndefinedNodeClass.new(self, 'node')
13
+ end
16
14
 
17
- def edges
18
- raise Errors::InvalidNodeClass.new(@node_class, Node) unless @node_class < Node
15
+ unless node_class <= GQL::Node
16
+ raise Errors::InvalidNodeClass.new(node_class, GQL::Node)
17
+ end
19
18
 
20
- items.map do |item|
21
- node = @node_class.new(edges_ast_node, item, @variables, __context)
22
- node.__value
19
+ Class.new(self).tap do |connection_class|
20
+ connection_class.node_class = node_class
21
+ end
23
22
  end
24
23
  end
25
24
 
26
- EdgesField.class_eval do
27
- def __value
28
- if @ast_node.fields
29
- __target
30
- else
31
- nil
25
+ def value_of_field(ast_field)
26
+ if ast_field.name == :edges
27
+ target.map do |item|
28
+ node = self.class.node_class.new(ast_field, item, variables, context)
29
+ node.value
32
30
  end
31
+ else
32
+ super
33
33
  end
34
34
  end
35
35
  end
data/lib/gql/errors.rb CHANGED
@@ -1,35 +1,39 @@
1
1
  require 'active_support/core_ext/array/conversions'
2
+ require 'active_support/core_ext/string/inflections'
2
3
 
3
4
  module GQL
4
5
  class Error < StandardError
5
6
  end
6
7
 
7
8
  module Errors
8
- class SchemaError < Error
9
+ class UndefinedRoot < Error
10
+ def initialize
11
+ super('Root node class is undefined. Define it with `GQL.root_node_class = MyRootNode`.')
12
+ end
9
13
  end
10
14
 
11
- class UndefinedRoot < SchemaError
12
- def initialize
13
- super('No root node class is known to the schema. Assign it with `GQL::Schema.root = MyRootNode`.')
15
+ class UndefinedNodeClass < Error
16
+ def initialize(node_class, name)
17
+ super("#{node_class} must define a #{name} class. Set it with `self.#{name}_class = My#{method.camelize}Class`.")
14
18
  end
15
19
  end
16
20
 
17
- class InvalidNodeClass < SchemaError
21
+ class InvalidNodeClass < Error
18
22
  def initialize(node_class, super_class)
19
- super("#{node_class} must be a subclass of #{super_class}.")
23
+ super("#{node_class} must be a (subclass of) #{super_class}.")
20
24
  end
21
25
  end
22
26
 
23
- class UndefinedType < SchemaError
27
+ class UndefinedFieldType < Error
24
28
  def initialize(name)
25
- types = Schema.fields.keys.sort.map { |name| "`#{name}`" }
29
+ types = GQL.field_types.keys.sort.map { |name| "`#{name}`" }
26
30
  types = types.size > 0 ? " Available types: #{types.to_sentence}." : ''
27
31
 
28
- super("The field type `#{name}` is not known to the schema. Define it with `GQL::Schema.fields[my_type] = MyFieldType`.#{types}")
32
+ super("The field type `#{name}` is undefined. Define it with `GQL.field_types[:#{name}] = My#{name.to_s.camelize}`.#{types}")
29
33
  end
30
34
  end
31
35
 
32
- class UndefinedCall < SchemaError
36
+ class UndefinedCall < Error
33
37
  def initialize(name, node_class)
34
38
  calls = node_class.call_classes.keys.sort.map { |name| "`#{name}`" }
35
39
  calls = calls.size > 0 ? " Available calls: #{calls.to_sentence}." : ''
@@ -38,7 +42,7 @@ module GQL
38
42
  end
39
43
  end
40
44
 
41
- class UndefinedField < SchemaError
45
+ class UndefinedField < Error
42
46
  def initialize(name, node_class)
43
47
  fields = node_class.field_classes.keys.sort.map { |name| "`#{name}`" }
44
48
  fields = fields.size > 0 ? " Available fields: #{fields.to_sentence}." : ''
data/lib/gql/executor.rb CHANGED
@@ -1,18 +1,19 @@
1
1
  module GQL
2
2
  class Executor
3
+ attr_reader :ast_node, :variables
4
+
3
5
  def initialize(ast_root)
4
- @ast_root = ast_root
5
- @variables = ast_root.variables
6
+ @ast_node = ast_root.node
7
+ @variables = ast_root.variables
6
8
  end
7
9
 
8
10
  def execute(context = {})
9
- root_class = Schema.root
11
+ node_class = GQL.root_node_class
10
12
 
11
- raise Errors::UndefinedRoot if root_class.nil?
12
- raise Errors::InvalidNodeClass.new(root_class, Node) unless root_class < Node
13
+ raise Errors::UndefinedRoot if node_class.nil?
13
14
 
14
- root = root_class.new(@ast_root, nil, @variables, context)
15
- root.__value
15
+ node = node_class.new(ast_node, nil, variables, context)
16
+ node.value
16
17
  end
17
18
  end
18
19
  end
data/lib/gql/field.rb CHANGED
@@ -1,7 +1,31 @@
1
+ require 'active_support/core_ext/class/attribute'
2
+
1
3
  module GQL
2
4
  class Field < Node
3
- def __raw_value
4
- __target
5
+ class Method
6
+ attr_reader :target, :context
7
+
8
+ def initialize(target, context)
9
+ @target, @context = target, context
10
+ end
11
+
12
+ def execute(method)
13
+ instance_exec(&method)
14
+ end
15
+ end
16
+
17
+ class_attribute :method, instance_accessor: false, instance_predicate: false
18
+
19
+ class << self
20
+ def build_class(method, connection_class, node_class)
21
+ Class.new(self).tap do |field_class|
22
+ field_class.method = method
23
+ end
24
+ end
25
+ end
26
+
27
+ def raw_value
28
+ target
5
29
  end
6
30
  end
7
31
  end
@@ -1,22 +1,36 @@
1
+ require 'active_support/core_ext/class/attribute'
2
+
1
3
  module GQL
2
4
  module Fields
3
5
  class Connection < Field
4
- def __value
5
- if @ast_node.fields
6
- __raw_value
7
- else
8
- super
6
+ class_attribute :connection_class, instance_accessor: false, instance_predicate: false
7
+
8
+ class << self
9
+ def build_class(method, connection_class, node_class)
10
+ connection_class ||= self.connection_class
11
+
12
+ if connection_class.nil?
13
+ raise Errors::UndefinedNodeClass.new(self, 'connection')
14
+ end
15
+
16
+ unless connection_class <= GQL::Connection
17
+ raise Errors::InvalidNodeClass.new(connection_class, GQL::Connection)
18
+ end
19
+
20
+ Class.new(self).tap do |field_class|
21
+ field_class.method = method
22
+ field_class.connection_class = connection_class.build_class(node_class)
23
+ end
9
24
  end
10
25
  end
11
26
 
12
- def __raw_value
13
- connection_class = self.class.const_get(:CONNECTION_CLASS)
14
- node_class = self.class.const_get(:NODE_CLASS)
15
-
16
- raise Errors::InvalidNodeClass.new(connection_class, GQL::Connection) unless connection_class <= GQL::Connection
27
+ def value_of_fields(*)
28
+ connection = self.class.connection_class.new(ast_node, target, variables, context)
29
+ connection.value
30
+ end
17
31
 
18
- connection = connection_class.new(node_class, @ast_node, __target, @variables, __context)
19
- connection.__value
32
+ def raw_value
33
+ nil
20
34
  end
21
35
  end
22
36
  end
@@ -1,17 +1,37 @@
1
+ require 'active_support/core_ext/class/attribute'
2
+
1
3
  module GQL
2
4
  module Fields
3
5
  class Object < Field
4
- def __value
5
- raise Errors::InvalidNodeClass.new(__node_class__, Node) unless __node_class__ < Node
6
+ class_attribute :node_class, instance_accessor: false, instance_predicate: false
6
7
 
7
- node = __node_class__.new(@ast_node, __target, @variables, __context)
8
- node.__value
9
- end
8
+ class << self
9
+ def build_class(method, connection_class, node_class)
10
+ node_class ||= self.node_class
11
+
12
+ if node_class.nil?
13
+ raise Errors::UndefinedNodeClass.new(self, 'node')
14
+ end
10
15
 
11
- private
12
- def __node_class__
13
- self.class.const_get :NODE_CLASS
16
+ unless node_class <= GQL::Node
17
+ raise Errors::InvalidNodeClass.new(node_class, GQL::Node)
18
+ end
19
+
20
+ Class.new(self).tap do |field_class|
21
+ field_class.method = method
22
+ field_class.node_class = node_class
23
+ end
14
24
  end
25
+ end
26
+
27
+ def value_of_fields(*)
28
+ node = self.class.node_class.new(ast_node, target, variables, context)
29
+ node.value
30
+ end
31
+
32
+ def raw_value
33
+ nil
34
+ end
15
35
  end
16
36
  end
17
37
  end