gql 0.0.2 → 0.0.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 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