graphql-libgraphqlparser 0.0.1
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 +7 -0
- data/.gitignore +5 -0
- data/.travis.yml +25 -0
- data/Gemfile +2 -0
- data/Guardfile +16 -0
- data/README.md +51 -0
- data/Rakefile +17 -0
- data/benchmark.rb +10 -0
- data/ext/libgraphqlparser/extconf.rb +6 -0
- data/ext/libgraphqlparser/libgraphqlparser.c +67 -0
- data/ext/libgraphqlparser/libgraphqlparser.h +13 -0
- data/ext/libgraphqlparser/visitor_functions.c +317 -0
- data/ext/libgraphqlparser/visitor_functions.h +31 -0
- data/graphql-libgraphqlparser.gemspec +30 -0
- data/lib/graphql/libgraphqlparser/builder.rb +69 -0
- data/lib/graphql/libgraphqlparser/monkey_patches/abstract_node.rb +132 -0
- data/lib/graphql/libgraphqlparser/version.rb +5 -0
- data/lib/graphql/libgraphqlparser.rb +26 -0
- data/test/graphql/libgraphqlparser_test.rb +231 -0
- data/test/test_helper.rb +6 -0
- metadata +205 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a36c8dfc90001ecf63d6032683987c72cea30a09
|
4
|
+
data.tar.gz: 1dc323ff5bd90ff440849ad4146761818bf32f04
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 087f862222ee9b94bc373f47d4333cf6df42ad12205c6a13c7f743fdd21ea86743eb1271e4487dd3b9be72f44627f69d0de36dc5fcb9e74a7cacddb4a6de2204
|
7
|
+
data.tar.gz: 4542c42448fb8e552b4a708592d083590120463c9de175b45ab55f8aa41cd28983c4543ceb4833463a7c39292dba11d47b20b077f32f54bb8832fe70454ed0b2
|
data/.travis.yml
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
language: ruby
|
2
|
+
cache: bundler
|
3
|
+
sudo: required
|
4
|
+
rvm:
|
5
|
+
- 2.1
|
6
|
+
- 2.2
|
7
|
+
addons:
|
8
|
+
apt:
|
9
|
+
packages:
|
10
|
+
- cmake
|
11
|
+
before_install:
|
12
|
+
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
13
|
+
- sudo apt-get -qq update
|
14
|
+
- sudo apt-get install build-essential
|
15
|
+
- sudo apt-get -qq install g++-5
|
16
|
+
- sudo unlink /usr/bin/g++ && sudo ln -s /usr/bin/g++-5 /usr/bin/g++
|
17
|
+
- g++ --version
|
18
|
+
- sudo apt-get install bison
|
19
|
+
- wget https://github.com/graphql/libgraphqlparser/archive/v0.4.0.tar.gz
|
20
|
+
- tar -xzvf v0.4.0.tar.gz
|
21
|
+
- cd libgraphqlparser-0.4.0/ && sudo cmake . && sudo make && sudo make install
|
22
|
+
- gem update --system
|
23
|
+
- gem install bundler
|
24
|
+
script:
|
25
|
+
- bundle exec rake
|
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
guard :bundler do
|
2
|
+
watch('Gemfile')
|
3
|
+
# Uncomment next line if your Gemfile contains the `gemspec' command.
|
4
|
+
watch(/^.+\.gemspec/)
|
5
|
+
end
|
6
|
+
|
7
|
+
guard :minitest do
|
8
|
+
watch(%r{^test/(.*)_test\.rb})
|
9
|
+
watch(%r{^lib/(.+)\.rb}) { |m| "test/#{m[1]}_test.rb" }
|
10
|
+
watch(%r{^test/test_helper\.rb}) { 'test' }
|
11
|
+
watch(%r{^test/support/.*\.rb}) { 'test' }
|
12
|
+
end
|
13
|
+
|
14
|
+
guard 'rake', task: 'compile' do
|
15
|
+
watch(%r{^ext/libgraphqlparser/.+$})
|
16
|
+
end
|
data/README.md
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# graphql-libgraphqlparser [](https://travis-ci.org/rmosolgo/graphql-libgraphqlparser-ruby)
|
2
|
+
|
3
|
+
Make [`graphql`](https://github.com/rmosolgo/graphql-ruby) faster with [`libgraphqlparser`](https://github.com/graphql/libgraphqlparser). Ruby bindings to a C-level GraphQL parser.
|
4
|
+
|
5
|
+
It's faster:
|
6
|
+
|
7
|
+
```
|
8
|
+
~/projects/graphql-libgraphqlparser $ be ruby benchmark.rb
|
9
|
+
user system total real
|
10
|
+
Ruby 1.140000 0.010000 1.150000 ( 1.161160)
|
11
|
+
C 0.000000 0.000000 0.000000 ( 0.009008)
|
12
|
+
~/projects/graphql-libgraphqlparser $ be ruby benchmark.rb
|
13
|
+
user system total real
|
14
|
+
Ruby 1.180000 0.000000 1.180000 ( 1.185929)
|
15
|
+
C 0.000000 0.000000 0.000000 ( 0.008688)
|
16
|
+
~/projects/graphql-libgraphqlparser $ be ruby benchmark.rb
|
17
|
+
user system total real
|
18
|
+
Ruby 1.220000 0.010000 1.230000 ( 1.233795)
|
19
|
+
C 0.010000 0.000000 0.010000 ( 0.008584)
|
20
|
+
```
|
21
|
+
|
22
|
+
## Installation
|
23
|
+
|
24
|
+
This gem depends on [libgraphqlparser](https://github.com/graphql/libgraphqlparser). You can install it a few ways:
|
25
|
+
|
26
|
+
- __Homebrew__: `brew install libgraphqlparser`
|
27
|
+
- __From Source__:
|
28
|
+
|
29
|
+
```
|
30
|
+
wget https://github.com/graphql/libgraphqlparser/archive/v0.4.0.tar.gz
|
31
|
+
tar -xzvf v0.4.0.tar.gz
|
32
|
+
cd libgraphqlparser-0.4.0/ && cmake . && make && make install
|
33
|
+
```
|
34
|
+
|
35
|
+
Then, install this gem:
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
gem "graphql-libgraphqlparser"
|
39
|
+
```
|
40
|
+
|
41
|
+
When you `require` this gem, it overrides `GraphQL.parse`:
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
require "graphql/libgraphqlparser"
|
45
|
+
```
|
46
|
+
|
47
|
+
## Todo
|
48
|
+
|
49
|
+
- Get directives from OperationDefinitions
|
50
|
+
- AbstractNode overrides are full of tension. Resolve that tension with GraphQL main.
|
51
|
+
- Node `#type` is sometimes a String, sometimes a Node. That should always be the same.
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'rake/extensiontask'
|
3
|
+
|
4
|
+
Bundler::GemHelper.install_tasks
|
5
|
+
|
6
|
+
require 'rake/testtask'
|
7
|
+
|
8
|
+
Rake::TestTask.new do |t|
|
9
|
+
t.libs << "test" << "lib"
|
10
|
+
t.pattern = "test/**/*_test.rb"
|
11
|
+
end
|
12
|
+
|
13
|
+
Rake::ExtensionTask.new "libgraphqlparser" do |ext|
|
14
|
+
ext.lib_dir = "lib/graphql/libgraphqlparser"
|
15
|
+
end
|
16
|
+
|
17
|
+
task default: [:clobber, :compile, :test]
|
data/benchmark.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'benchmark'
|
2
|
+
require 'graphql'
|
3
|
+
require 'graphql/libgraphqlparser'
|
4
|
+
|
5
|
+
query_string = GraphQL::Introspection::INTROSPECTION_QUERY
|
6
|
+
|
7
|
+
Benchmark.bm(7) do |x|
|
8
|
+
x.report("Ruby") { 20.times { GraphQL.parse_without_libgraphqlparser(query_string) } }
|
9
|
+
x.report("C") { 20.times { GraphQL.parse(query_string) } }
|
10
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
#include "libgraphqlparser.h"
|
2
|
+
#include "visitor_functions.h"
|
3
|
+
|
4
|
+
#define ATTACH_CALLBACKS(node_name) \
|
5
|
+
Libgraphqlparser_Callbacks.visit_##node_name = node_name##_begin_visit; \
|
6
|
+
Libgraphqlparser_Callbacks.end_visit_##node_name = node_name##_end_visit; \
|
7
|
+
|
8
|
+
VALUE Libgraphqlparser_ParseError;
|
9
|
+
VALUE Libgraphqlparser_Builder;
|
10
|
+
|
11
|
+
static struct GraphQLAstVisitorCallbacks Libgraphqlparser_Callbacks;
|
12
|
+
|
13
|
+
// Given a Ruby querystring, return a
|
14
|
+
// GraphQL::Nodes::Document instance.
|
15
|
+
VALUE GraphQL_Libgraphqlparser_parse(VALUE self, VALUE query_string) {
|
16
|
+
const char* c_query_string = StringValuePtr(query_string);
|
17
|
+
const char* parse_error_message;
|
18
|
+
VALUE exception;
|
19
|
+
VALUE builder = Qnil;
|
20
|
+
|
21
|
+
struct GraphQLAstNode *parse_result = graphql_parse_string(c_query_string, &parse_error_message);
|
22
|
+
|
23
|
+
if (parse_result == NULL) {
|
24
|
+
exception = rb_exc_new_cstr(Libgraphqlparser_ParseError, parse_error_message);
|
25
|
+
graphql_error_free(parse_error_message);
|
26
|
+
rb_exc_raise(exception);
|
27
|
+
} else {
|
28
|
+
builder = rb_class_new_instance(0, NULL, Libgraphqlparser_Builder);
|
29
|
+
graphql_node_visit(parse_result, &Libgraphqlparser_Callbacks, (void*)builder);
|
30
|
+
}
|
31
|
+
|
32
|
+
return builder;
|
33
|
+
}
|
34
|
+
|
35
|
+
// Initialize the extension
|
36
|
+
void Init_libgraphqlparser() {
|
37
|
+
VALUE GraphQL = rb_define_module("GraphQL");
|
38
|
+
VALUE Libgraphqlparser = rb_define_module_under(GraphQL, "Libgraphqlparser");
|
39
|
+
rb_define_singleton_method(Libgraphqlparser, "builder_parse", GraphQL_Libgraphqlparser_parse, 1);
|
40
|
+
|
41
|
+
Libgraphqlparser_ParseError = rb_define_class_under(Libgraphqlparser, "ParseError", rb_eStandardError);
|
42
|
+
Libgraphqlparser_Builder = rb_const_get(Libgraphqlparser, rb_intern("Builder"));
|
43
|
+
|
44
|
+
init_visitor_functions();
|
45
|
+
// Attach the functions to the Callbacks struct
|
46
|
+
ATTACH_CALLBACKS(document);
|
47
|
+
ATTACH_CALLBACKS(operation_definition);
|
48
|
+
ATTACH_CALLBACKS(variable_definition);
|
49
|
+
ATTACH_CALLBACKS(fragment_definition);
|
50
|
+
ATTACH_CALLBACKS(variable);
|
51
|
+
ATTACH_CALLBACKS(field);
|
52
|
+
ATTACH_CALLBACKS(directive);
|
53
|
+
ATTACH_CALLBACKS(argument);
|
54
|
+
ATTACH_CALLBACKS(fragment_spread);
|
55
|
+
ATTACH_CALLBACKS(inline_fragment);
|
56
|
+
ATTACH_CALLBACKS(list_type);
|
57
|
+
ATTACH_CALLBACKS(non_null_type);
|
58
|
+
ATTACH_CALLBACKS(named_type);
|
59
|
+
ATTACH_CALLBACKS(float_value);
|
60
|
+
ATTACH_CALLBACKS(int_value);
|
61
|
+
ATTACH_CALLBACKS(boolean_value);
|
62
|
+
ATTACH_CALLBACKS(string_value);
|
63
|
+
ATTACH_CALLBACKS(enum_value);
|
64
|
+
ATTACH_CALLBACKS(array_value);
|
65
|
+
ATTACH_CALLBACKS(object_value);
|
66
|
+
ATTACH_CALLBACKS(object_field);
|
67
|
+
}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
#ifndef Libgraphqlparser_EXT_H
|
2
|
+
#define Libgraphqlparser_EXT_H
|
3
|
+
|
4
|
+
#include <ruby.h>
|
5
|
+
#include <ruby/encoding.h>
|
6
|
+
#include <c/GraphQLParser.h>
|
7
|
+
#include <c/GraphQLAstNode.h>
|
8
|
+
#include <c/GraphQLAstVisitor.h>
|
9
|
+
#include <c/GraphQLAst.h>
|
10
|
+
|
11
|
+
void Init_libgraphqlparser();
|
12
|
+
|
13
|
+
#endif
|
@@ -0,0 +1,317 @@
|
|
1
|
+
#include "libgraphqlparser.h"
|
2
|
+
|
3
|
+
// These macros are a bit janky,
|
4
|
+
// they depend on the function signature
|
5
|
+
// being the same all the time: `(GraphQLAstNode* node, void* builder_ptr)`.
|
6
|
+
//
|
7
|
+
// Then they provide `rb_node` that you can work on in the function body.
|
8
|
+
#define BEGIN(node_name_string) \
|
9
|
+
VALUE rb_node = rb_funcall( \
|
10
|
+
(VALUE) builder_ptr, \
|
11
|
+
begin_visit_intern, \
|
12
|
+
1, \
|
13
|
+
rb_str_new2(node_name_string) \
|
14
|
+
); \
|
15
|
+
struct GraphQLAstLocation* location = malloc(sizeof(struct GraphQLAstLocation)); \
|
16
|
+
graphql_node_get_location((struct GraphQLAstNode *)node, location); \
|
17
|
+
rb_funcall(rb_node, line_set_intern, 1, INT2NUM(location->beginLine)); \
|
18
|
+
rb_funcall(rb_node, col_set_intern, 1, INT2NUM(location->beginColumn)); \
|
19
|
+
free(location); \
|
20
|
+
|
21
|
+
#define END \
|
22
|
+
rb_funcall( \
|
23
|
+
(VALUE) builder_ptr, \
|
24
|
+
end_visit_intern, \
|
25
|
+
0 \
|
26
|
+
); \
|
27
|
+
|
28
|
+
#define ADD_LITERAL(rb_value) \
|
29
|
+
rb_funcall( \
|
30
|
+
(VALUE) builder_ptr, \
|
31
|
+
add_value_intern, \
|
32
|
+
1, \
|
33
|
+
rb_value \
|
34
|
+
); \
|
35
|
+
|
36
|
+
|
37
|
+
#define ASSIGN_NAME(get_name_fn) \
|
38
|
+
rb_funcall(rb_node, name_set_intern, 1, \
|
39
|
+
rb_str_new2( \
|
40
|
+
GraphQLAstName_get_value( \
|
41
|
+
get_name_fn(node) \
|
42
|
+
) \
|
43
|
+
) \
|
44
|
+
); \
|
45
|
+
|
46
|
+
#define ASSIGN_NAMED_TYPE(get_type_fn) \
|
47
|
+
rb_funcall( \
|
48
|
+
rb_node, \
|
49
|
+
type_set_intern, \
|
50
|
+
1, \
|
51
|
+
rb_str_new2( \
|
52
|
+
GraphQLAstName_get_value( \
|
53
|
+
GraphQLAstNamedType_get_name( \
|
54
|
+
get_type_fn(node) \
|
55
|
+
) \
|
56
|
+
) \
|
57
|
+
) \
|
58
|
+
); \
|
59
|
+
|
60
|
+
VALUE type_set_intern, name_set_intern, add_value_intern, end_visit_intern, begin_visit_intern, line_set_intern, col_set_intern;
|
61
|
+
void init_visitor_functions() {
|
62
|
+
type_set_intern = rb_intern("type=");
|
63
|
+
name_set_intern = rb_intern("name=");
|
64
|
+
add_value_intern = rb_intern("add_value");
|
65
|
+
end_visit_intern = rb_intern("end_visit");
|
66
|
+
begin_visit_intern = rb_intern("begin_visit");
|
67
|
+
line_set_intern = rb_intern("line=");
|
68
|
+
col_set_intern = rb_intern("col=");
|
69
|
+
}
|
70
|
+
|
71
|
+
// There's a `begin_visit` and `end_visit` for each node.
|
72
|
+
// Some of the end_visit callbacks are empty but that's ok,
|
73
|
+
// It lets us use macros in the other files.
|
74
|
+
|
75
|
+
int document_begin_visit(const struct GraphQLAstDocument* node, void* builder_ptr) {
|
76
|
+
BEGIN("Document")
|
77
|
+
return 1;
|
78
|
+
}
|
79
|
+
|
80
|
+
void document_end_visit(const struct GraphQLAstDocument* node, void* builder_ptr) {
|
81
|
+
}
|
82
|
+
|
83
|
+
int operation_definition_begin_visit(const struct GraphQLAstOperationDefinition* node, void* builder_ptr) {
|
84
|
+
const struct GraphQLAstName* ast_operation_name;
|
85
|
+
const char* operation_type;
|
86
|
+
VALUE operation_type_str;
|
87
|
+
|
88
|
+
BEGIN("OperationDefinition")
|
89
|
+
|
90
|
+
ast_operation_name = GraphQLAstOperationDefinition_get_name(node);
|
91
|
+
if (ast_operation_name) {
|
92
|
+
const char* operation_name = GraphQLAstName_get_value(ast_operation_name);
|
93
|
+
rb_funcall(rb_node, name_set_intern, 1, rb_str_new2(operation_name));
|
94
|
+
}
|
95
|
+
|
96
|
+
operation_type = GraphQLAstOperationDefinition_get_operation(node);
|
97
|
+
|
98
|
+
if (operation_type) {
|
99
|
+
operation_type_str = rb_str_new2(operation_type);
|
100
|
+
} else {
|
101
|
+
operation_type_str = rb_str_new2("query");
|
102
|
+
}
|
103
|
+
|
104
|
+
rb_funcall(rb_node, rb_intern("operation_type="), 1, operation_type_str);
|
105
|
+
|
106
|
+
return 1;
|
107
|
+
}
|
108
|
+
|
109
|
+
void operation_definition_end_visit(const struct GraphQLAstOperationDefinition* node, void* builder_ptr) {
|
110
|
+
END
|
111
|
+
}
|
112
|
+
|
113
|
+
int variable_definition_begin_visit(const struct GraphQLAstVariableDefinition* node, void* builder_ptr) {
|
114
|
+
BEGIN("VariableDefinition")
|
115
|
+
return 1;
|
116
|
+
}
|
117
|
+
|
118
|
+
void variable_definition_end_visit(const struct GraphQLAstVariableDefinition* node, void* builder_ptr) {
|
119
|
+
END
|
120
|
+
}
|
121
|
+
|
122
|
+
|
123
|
+
int fragment_definition_begin_visit(const struct GraphQLAstFragmentDefinition* node, void* builder_ptr) {
|
124
|
+
BEGIN("FragmentDefinition")
|
125
|
+
ASSIGN_NAME(GraphQLAstFragmentDefinition_get_name)
|
126
|
+
ASSIGN_NAMED_TYPE(GraphQLAstFragmentDefinition_get_type_condition)
|
127
|
+
return 1;
|
128
|
+
}
|
129
|
+
|
130
|
+
void fragment_definition_end_visit(const struct GraphQLAstFragmentDefinition* node, void* builder_ptr) {
|
131
|
+
END
|
132
|
+
}
|
133
|
+
|
134
|
+
|
135
|
+
int variable_begin_visit(const struct GraphQLAstVariable* node, void* builder_ptr) {
|
136
|
+
BEGIN("VariableIdentifier")
|
137
|
+
// This might actually assign the name of a VariableDefinition:
|
138
|
+
ASSIGN_NAME(GraphQLAstVariable_get_name)
|
139
|
+
return 1;
|
140
|
+
}
|
141
|
+
|
142
|
+
void variable_end_visit(const struct GraphQLAstVariable* node, void* builder_ptr) {
|
143
|
+
END
|
144
|
+
}
|
145
|
+
|
146
|
+
int field_begin_visit(const struct GraphQLAstField* node, void* builder_ptr) {
|
147
|
+
const struct GraphQLAstName* ast_field_alias;
|
148
|
+
const char* str_field_alias;
|
149
|
+
BEGIN("Field")
|
150
|
+
ASSIGN_NAME(GraphQLAstField_get_name)
|
151
|
+
|
152
|
+
ast_field_alias = GraphQLAstField_get_alias(node);
|
153
|
+
if (ast_field_alias) {
|
154
|
+
str_field_alias = GraphQLAstName_get_value(ast_field_alias);
|
155
|
+
rb_funcall(rb_node, rb_intern("alias="), 1, rb_str_new2(str_field_alias));
|
156
|
+
}
|
157
|
+
return 1;
|
158
|
+
}
|
159
|
+
|
160
|
+
void field_end_visit(const struct GraphQLAstField* node, void* builder_ptr) {
|
161
|
+
END
|
162
|
+
}
|
163
|
+
|
164
|
+
int directive_begin_visit(const struct GraphQLAstDirective* node, void* builder_ptr) {
|
165
|
+
BEGIN("Directive")
|
166
|
+
ASSIGN_NAME(GraphQLAstDirective_get_name)
|
167
|
+
return 1;
|
168
|
+
}
|
169
|
+
|
170
|
+
void directive_end_visit(const struct GraphQLAstDirective* node, void* builder_ptr) {
|
171
|
+
END
|
172
|
+
}
|
173
|
+
|
174
|
+
int argument_begin_visit(const struct GraphQLAstArgument* node, void* builder_ptr) {
|
175
|
+
BEGIN("Argument")
|
176
|
+
ASSIGN_NAME(GraphQLAstArgument_get_name)
|
177
|
+
return 1;
|
178
|
+
}
|
179
|
+
|
180
|
+
void argument_end_visit(const struct GraphQLAstArgument* node, void* builder_ptr) {
|
181
|
+
END
|
182
|
+
}
|
183
|
+
|
184
|
+
int fragment_spread_begin_visit(const struct GraphQLAstFragmentSpread* node, void* builder_ptr) {
|
185
|
+
BEGIN("FragmentSpread")
|
186
|
+
ASSIGN_NAME(GraphQLAstFragmentSpread_get_name)
|
187
|
+
return 1;
|
188
|
+
}
|
189
|
+
|
190
|
+
void fragment_spread_end_visit(const struct GraphQLAstFragmentSpread* node, void* builder_ptr) {
|
191
|
+
END
|
192
|
+
}
|
193
|
+
|
194
|
+
int inline_fragment_begin_visit(const struct GraphQLAstInlineFragment* node, void* builder_ptr) {
|
195
|
+
BEGIN("InlineFragment")
|
196
|
+
ASSIGN_NAMED_TYPE(GraphQLAstInlineFragment_get_type_condition)
|
197
|
+
return 1;
|
198
|
+
}
|
199
|
+
|
200
|
+
void inline_fragment_end_visit(const struct GraphQLAstInlineFragment* node, void* builder_ptr) {
|
201
|
+
END
|
202
|
+
}
|
203
|
+
|
204
|
+
int list_type_begin_visit(const struct GraphQLAstListType* node, void* builder_ptr) {
|
205
|
+
BEGIN("ListType")
|
206
|
+
return 1;
|
207
|
+
}
|
208
|
+
|
209
|
+
void list_type_end_visit(const struct GraphQLAstListType* node, void* builder_ptr) {
|
210
|
+
END
|
211
|
+
}
|
212
|
+
|
213
|
+
|
214
|
+
int non_null_type_begin_visit(const struct GraphQLAstNonNullType* node, void* builder_ptr) {
|
215
|
+
BEGIN("NonNullType")
|
216
|
+
return 1;
|
217
|
+
}
|
218
|
+
|
219
|
+
void non_null_type_end_visit(const struct GraphQLAstNonNullType* node, void* builder_ptr) {
|
220
|
+
END
|
221
|
+
}
|
222
|
+
|
223
|
+
int named_type_begin_visit(const struct GraphQLAstNamedType* node, void* builder_ptr) {
|
224
|
+
BEGIN("TypeName")
|
225
|
+
ASSIGN_NAME(GraphQLAstNamedType_get_name)
|
226
|
+
return 1;
|
227
|
+
}
|
228
|
+
|
229
|
+
void named_type_end_visit(const struct GraphQLAstNamedType* node, void* builder_ptr) {
|
230
|
+
END
|
231
|
+
}
|
232
|
+
|
233
|
+
|
234
|
+
int float_value_begin_visit(const struct GraphQLAstFloatValue* node, void* builder_ptr) {
|
235
|
+
const char* str_float = GraphQLAstFloatValue_get_value(node);
|
236
|
+
VALUE rb_float = rb_funcall(rb_str_new2(str_float), rb_intern("to_f"), 0);
|
237
|
+
ADD_LITERAL(rb_float);
|
238
|
+
return 1;
|
239
|
+
}
|
240
|
+
|
241
|
+
void float_value_end_visit(const struct GraphQLAstFloatValue* node, void* builder_ptr) {
|
242
|
+
}
|
243
|
+
|
244
|
+
int int_value_begin_visit(const struct GraphQLAstIntValue* node, void* builder_ptr) {
|
245
|
+
const char* str_int = GraphQLAstIntValue_get_value(node);
|
246
|
+
VALUE rb_int = rb_funcall(rb_str_new2(str_int), rb_intern("to_i"), 0);
|
247
|
+
ADD_LITERAL(rb_int);
|
248
|
+
return 1;
|
249
|
+
}
|
250
|
+
|
251
|
+
void int_value_end_visit(const struct GraphQLAstIntValue* node, void* builder_ptr) {
|
252
|
+
}
|
253
|
+
|
254
|
+
int boolean_value_begin_visit(const struct GraphQLAstBooleanValue* node, void* builder_ptr) {
|
255
|
+
const int bool_value = GraphQLAstBooleanValue_get_value(node);
|
256
|
+
if (bool_value) {
|
257
|
+
ADD_LITERAL(Qtrue)
|
258
|
+
} else {
|
259
|
+
ADD_LITERAL(Qfalse)
|
260
|
+
}
|
261
|
+
return 1;
|
262
|
+
}
|
263
|
+
|
264
|
+
void boolean_value_end_visit(const struct GraphQLAstBooleanValue* node, void* builder_ptr) {
|
265
|
+
}
|
266
|
+
|
267
|
+
int string_value_begin_visit(const struct GraphQLAstStringValue* node, void* builder_ptr) {
|
268
|
+
const char* str_value = GraphQLAstStringValue_get_value(node);
|
269
|
+
VALUE rb_string = rb_str_new2(str_value);
|
270
|
+
int enc = rb_enc_find_index("UTF-8");
|
271
|
+
rb_enc_associate_index(rb_string, enc);
|
272
|
+
ADD_LITERAL(rb_string);
|
273
|
+
return 1;
|
274
|
+
}
|
275
|
+
|
276
|
+
void string_value_end_visit(const struct GraphQLAstStringValue* node, void* builder_ptr) {
|
277
|
+
}
|
278
|
+
|
279
|
+
int enum_value_begin_visit(const struct GraphQLAstEnumValue* node, void* builder_ptr) {
|
280
|
+
const char* str_value = GraphQLAstEnumValue_get_value(node);
|
281
|
+
VALUE rb_string = rb_str_new2(str_value);
|
282
|
+
int enc = rb_enc_find_index("UTF-8");
|
283
|
+
rb_enc_associate_index(rb_string, enc);
|
284
|
+
ADD_LITERAL(rb_string);
|
285
|
+
return 1;
|
286
|
+
}
|
287
|
+
|
288
|
+
void enum_value_end_visit(const struct GraphQLAstEnumValue* node, void* builder_ptr) {
|
289
|
+
}
|
290
|
+
|
291
|
+
int array_value_begin_visit(const struct GraphQLAstArrayValue* node, void* builder_ptr) {
|
292
|
+
BEGIN("ArrayLiteral")
|
293
|
+
return 1;
|
294
|
+
}
|
295
|
+
|
296
|
+
void array_value_end_visit(const struct GraphQLAstArrayValue* node, void* builder_ptr) {
|
297
|
+
END
|
298
|
+
}
|
299
|
+
|
300
|
+
int object_value_begin_visit(const struct GraphQLAstObjectValue* node, void* builder_ptr) {
|
301
|
+
BEGIN("InputObject")
|
302
|
+
return 1;
|
303
|
+
}
|
304
|
+
|
305
|
+
void object_value_end_visit(const struct GraphQLAstObjectValue* node, void* builder_ptr) {
|
306
|
+
END
|
307
|
+
}
|
308
|
+
|
309
|
+
int object_field_begin_visit(const struct GraphQLAstObjectField* node, void* builder_ptr) {
|
310
|
+
BEGIN("Argument")
|
311
|
+
ASSIGN_NAME(GraphQLAstObjectField_get_name)
|
312
|
+
return 1;
|
313
|
+
}
|
314
|
+
|
315
|
+
void object_field_end_visit(const struct GraphQLAstObjectField* node, void* builder_ptr) {
|
316
|
+
END
|
317
|
+
}
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#ifndef Libgraphqlparser_visitor_functions_H
|
2
|
+
#define Libgraphqlparser_visitor_functions_H
|
3
|
+
|
4
|
+
#define VISITOR_CALLBACKS(snake_name, camel_name) \
|
5
|
+
int snake_name##_begin_visit(const struct GraphQLAst##camel_name* document, void* builder_ptr); \
|
6
|
+
void snake_name##_end_visit(const struct GraphQLAst##camel_name* document, void* builder_ptr); \
|
7
|
+
|
8
|
+
void init_visitor_functions();
|
9
|
+
VISITOR_CALLBACKS(document, Document);
|
10
|
+
VISITOR_CALLBACKS(operation_definition, OperationDefinition);
|
11
|
+
VISITOR_CALLBACKS(variable_definition, VariableDefinition);
|
12
|
+
VISITOR_CALLBACKS(fragment_definition, FragmentDefinition);
|
13
|
+
VISITOR_CALLBACKS(variable, Variable);
|
14
|
+
VISITOR_CALLBACKS(field, Field);
|
15
|
+
VISITOR_CALLBACKS(directive, Directive);
|
16
|
+
VISITOR_CALLBACKS(argument, Argument);
|
17
|
+
VISITOR_CALLBACKS(fragment_spread, FragmentSpread);
|
18
|
+
VISITOR_CALLBACKS(inline_fragment, InlineFragment);
|
19
|
+
VISITOR_CALLBACKS(list_type, ListType);
|
20
|
+
VISITOR_CALLBACKS(non_null_type, NonNullType);
|
21
|
+
VISITOR_CALLBACKS(named_type, NamedType);
|
22
|
+
VISITOR_CALLBACKS(float_value, FloatValue);
|
23
|
+
VISITOR_CALLBACKS(int_value, IntValue);
|
24
|
+
VISITOR_CALLBACKS(boolean_value, BooleanValue);
|
25
|
+
VISITOR_CALLBACKS(string_value, StringValue);
|
26
|
+
VISITOR_CALLBACKS(enum_value, EnumValue);
|
27
|
+
VISITOR_CALLBACKS(array_value, ArrayValue);
|
28
|
+
VISITOR_CALLBACKS(object_value, ObjectValue);
|
29
|
+
VISITOR_CALLBACKS(object_field, ObjectField);
|
30
|
+
|
31
|
+
#endif
|
@@ -0,0 +1,30 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'graphql/libgraphqlparser/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'graphql-libgraphqlparser'
|
7
|
+
spec.version = GraphQL::Libgraphqlparser::VERSION
|
8
|
+
spec.authors = ['Robert Mosolgo']
|
9
|
+
spec.homepage = 'https://github.com/rmosolgo/graphql-libgraphqlparser-ruby'
|
10
|
+
spec.email = ['rdmosolgo@gmail.com']
|
11
|
+
spec.summary = "Use Libgraphqlparser to parse queries for the GraphQL gem"
|
12
|
+
spec.license = "minitest"
|
13
|
+
|
14
|
+
spec.files = `git ls-files -z`.split("\x0")
|
15
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
16
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
17
|
+
spec.require_paths = ['lib']
|
18
|
+
|
19
|
+
spec.add_runtime_dependency 'graphql', '~> 0.10.0'
|
20
|
+
|
21
|
+
spec.add_development_dependency 'bundler', '~> 1.0'
|
22
|
+
spec.add_development_dependency "guard", "~> 2.12"
|
23
|
+
spec.add_development_dependency "guard-bundler", "~> 2.1"
|
24
|
+
spec.add_development_dependency "guard-minitest", "~> 2.4"
|
25
|
+
spec.add_development_dependency "guard-rake", "~> 1.0"
|
26
|
+
spec.add_development_dependency 'minitest', '~> 5.8'
|
27
|
+
spec.add_development_dependency "minitest-reporters", "~>1.0"
|
28
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
29
|
+
spec.add_development_dependency 'rake-compiler', '~> 0.9'
|
30
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module GraphQL
|
2
|
+
module Libgraphqlparser
|
3
|
+
# Keeps a stack of parse results, exposing the latest one.
|
4
|
+
# The C parser can call methods on this object, assuming
|
5
|
+
# they'll be applied to the right object.
|
6
|
+
class Builder
|
7
|
+
include GraphQL::Language
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@ast_stack = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def document
|
14
|
+
@ast_stack.first
|
15
|
+
end
|
16
|
+
|
17
|
+
def current
|
18
|
+
@ast_stack.last
|
19
|
+
end
|
20
|
+
|
21
|
+
def begin_visit(node_class_name)
|
22
|
+
# p "--> BEGIN #{node_class_name}"
|
23
|
+
node_class = Nodes.const_get(node_class_name)
|
24
|
+
node = node_class.new
|
25
|
+
case node
|
26
|
+
when Nodes::OperationDefinition, Nodes::FragmentDefinition
|
27
|
+
current.definitions << node
|
28
|
+
when Nodes::VariableDefinition
|
29
|
+
current.variables << node
|
30
|
+
when Nodes::VariableIdentifier
|
31
|
+
if current.is_a?(Nodes::VariableDefinition)
|
32
|
+
node = current
|
33
|
+
else
|
34
|
+
current.value = node
|
35
|
+
end
|
36
|
+
when Nodes::Directive
|
37
|
+
current.directives << node
|
38
|
+
when Nodes::Argument
|
39
|
+
current.arguments << node
|
40
|
+
when Nodes::InlineFragment, Nodes::FragmentSpread, Nodes::Field
|
41
|
+
current.selections << node
|
42
|
+
when Nodes::TypeName, Nodes::ListType, Nodes::NonNullType
|
43
|
+
# Using ||= because FragmentDefinition has already assigned
|
44
|
+
# this as a plain string :(
|
45
|
+
current.type ||= node
|
46
|
+
when Nodes::ArrayLiteral
|
47
|
+
# mutability! 🎉
|
48
|
+
current.value = node.values
|
49
|
+
when Nodes::InputObject
|
50
|
+
current.value = node
|
51
|
+
end
|
52
|
+
|
53
|
+
@ast_stack.push(node)
|
54
|
+
node
|
55
|
+
end
|
56
|
+
|
57
|
+
def end_visit
|
58
|
+
removed = @ast_stack.pop
|
59
|
+
# p "--> END #{removed}"
|
60
|
+
removed
|
61
|
+
end
|
62
|
+
|
63
|
+
# This is for convenience from C
|
64
|
+
def add_value(string_value)
|
65
|
+
current.value = string_value
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
module GraphQL
|
2
|
+
module Language
|
3
|
+
module Nodes
|
4
|
+
class AbstractNode
|
5
|
+
alias :old_initialize :initialize
|
6
|
+
# Allow initialize with no args
|
7
|
+
def initialize(*args)
|
8
|
+
if args.any?
|
9
|
+
old_initialize(*args)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def position
|
14
|
+
[line, col]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Document = AbstractNode.create(:parts)
|
19
|
+
class Document
|
20
|
+
def definitions
|
21
|
+
@parts ||= []
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# OperationDefinition = AbstractNode.create(:operation_type, :name, :variables, :directives, :selections)
|
26
|
+
class OperationDefinition
|
27
|
+
def variables
|
28
|
+
@variables ||= []
|
29
|
+
end
|
30
|
+
|
31
|
+
def selections
|
32
|
+
@selections ||= []
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Variable = AbstractNode.create(:name, :type, :default_value)
|
37
|
+
VariableDefinition = Variable
|
38
|
+
class VariableDefinition
|
39
|
+
# Make it behave like an Argument
|
40
|
+
def value=(new_value)
|
41
|
+
@default_value = new_value
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# VariableIdentifier = AbstractNode.create(:name)
|
46
|
+
|
47
|
+
# FragmentDefinition = AbstractNode.create(:name, :type, :directives, :selections)
|
48
|
+
class FragmentDefinition
|
49
|
+
def selections
|
50
|
+
@selections ||= []
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Field = AbstractNode.create(:name, :alias, :arguments, :directives, :selections)
|
55
|
+
class Field
|
56
|
+
def selections
|
57
|
+
@selections ||= []
|
58
|
+
end
|
59
|
+
|
60
|
+
def directives
|
61
|
+
@directives ||= []
|
62
|
+
end
|
63
|
+
|
64
|
+
def arguments
|
65
|
+
@arguments ||= []
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Directive = AbstractNode.create(:name, :arguments)
|
70
|
+
class Directive
|
71
|
+
def arguments
|
72
|
+
@arguments ||= []
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# FragmentSpread = AbstractNode.create(:name, :directives)
|
77
|
+
class FragmentSpread
|
78
|
+
def directives
|
79
|
+
@directives ||= []
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# InlineFragment = AbstractNode.create(:type, :directives, :selections)
|
84
|
+
class InlineFragment
|
85
|
+
def directives
|
86
|
+
@directives ||= []
|
87
|
+
end
|
88
|
+
def selections
|
89
|
+
@selections ||= []
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# ListType = AbstractNode.create(:of_type)
|
94
|
+
# NonNullType = AbstractNode.create(:of_type)
|
95
|
+
# TypeName = AbstractNode.create(:name)
|
96
|
+
class ListType
|
97
|
+
def type=(inner_type)
|
98
|
+
self.of_type = inner_type
|
99
|
+
end
|
100
|
+
def type; self.of_type; end
|
101
|
+
end
|
102
|
+
class NonNullType
|
103
|
+
def type=(inner_type)
|
104
|
+
self.of_type = inner_type
|
105
|
+
end
|
106
|
+
def type; self.of_type; end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Argument = AbstractNode.create(:name, :value)
|
110
|
+
# Enum = AbstractNode.create(:name)
|
111
|
+
class InputObject
|
112
|
+
def arguments
|
113
|
+
@pairs ||= []
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
class ArrayLiteral < AbstractNode
|
118
|
+
attr_reader :values
|
119
|
+
|
120
|
+
def initialize
|
121
|
+
@values = []
|
122
|
+
end
|
123
|
+
|
124
|
+
# This makes it behave like Argument,
|
125
|
+
# while it's on the stack it can gobble up values
|
126
|
+
def value=(new_value)
|
127
|
+
values << new_value
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'graphql'
|
2
|
+
require 'graphql/libgraphqlparser/builder'
|
3
|
+
require 'graphql/libgraphqlparser/libgraphqlparser'
|
4
|
+
require 'graphql/libgraphqlparser/monkey_patches/abstract_node'
|
5
|
+
require 'graphql/libgraphqlparser/version'
|
6
|
+
|
7
|
+
module GraphQL
|
8
|
+
module Libgraphqlparser
|
9
|
+
def self.parse(string)
|
10
|
+
builder = builder_parse(string)
|
11
|
+
builder.document
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def parse_with_libgraphqlparser(string)
|
17
|
+
Libgraphqlparser.parse(string)
|
18
|
+
end
|
19
|
+
|
20
|
+
alias :parse_without_libgraphqlparser :parse
|
21
|
+
|
22
|
+
def parse(string, as: nil)
|
23
|
+
parse_with_libgraphqlparser(string)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,231 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe GraphQL::Libgraphqlparser do
|
4
|
+
let(:document) { GraphQL::Libgraphqlparser.parse(query_string) }
|
5
|
+
let(:query_string) {%|
|
6
|
+
query getStuff($someVar: Int = 1, $anotherVar: [String!] ) {
|
7
|
+
myField: someField(someArg: $someVar, ok: 1.4) @skip(if: $anotherVar) @thing(or: "Whatever")
|
8
|
+
|
9
|
+
anotherField(someArg: [1,2,3]) {
|
10
|
+
nestedField
|
11
|
+
... moreNestedFields @skip(if: true)
|
12
|
+
}
|
13
|
+
|
14
|
+
... on OtherType @include(unless: false){
|
15
|
+
field
|
16
|
+
anotherField
|
17
|
+
}
|
18
|
+
|
19
|
+
}
|
20
|
+
|
21
|
+
fragment moreNestedFields on NestedType {
|
22
|
+
anotherNestedField
|
23
|
+
}
|
24
|
+
|}
|
25
|
+
|
26
|
+
describe '.parse' do
|
27
|
+
it 'parses queries' do
|
28
|
+
assert document
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "visited nodes" do
|
32
|
+
let(:query) { document.definitions.first }
|
33
|
+
let(:fragment_def) { document.definitions.last }
|
34
|
+
|
35
|
+
it "creates a valid document" do
|
36
|
+
assert document.is_a?(GraphQL::Language::Nodes::Document)
|
37
|
+
assert_equal 2, document.definitions.length
|
38
|
+
end
|
39
|
+
|
40
|
+
it "creates a valid operation" do
|
41
|
+
assert query.is_a?(GraphQL::Language::Nodes::OperationDefinition)
|
42
|
+
assert_equal "getStuff", query.name
|
43
|
+
assert_equal "query", query.operation_type
|
44
|
+
assert_equal 2, query.variables.length
|
45
|
+
assert_equal 3, query.selections.length
|
46
|
+
assert_equal [2, 5], [query.line, query.col]
|
47
|
+
end
|
48
|
+
|
49
|
+
it "creates a valid fragment definition" do
|
50
|
+
assert fragment_def.is_a?(GraphQL::Language::Nodes::FragmentDefinition)
|
51
|
+
assert_equal "moreNestedFields", fragment_def.name
|
52
|
+
assert_equal 1, fragment_def.selections.length
|
53
|
+
assert_equal "NestedType", fragment_def.type
|
54
|
+
assert_equal [17, 5], fragment_def.position
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "variable definitions" do
|
58
|
+
let(:optional_var) { query.variables.first }
|
59
|
+
it "gets name and type" do
|
60
|
+
assert_equal "someVar", optional_var.name
|
61
|
+
assert_equal "Int", optional_var.type.name
|
62
|
+
end
|
63
|
+
|
64
|
+
it "gets default value" do
|
65
|
+
assert_equal 1, optional_var.default_value
|
66
|
+
end
|
67
|
+
|
68
|
+
it "gets position info" do
|
69
|
+
assert_equal [2, 20], optional_var.position
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "fields" do
|
74
|
+
let(:leaf_field) { query.selections.first }
|
75
|
+
let(:parent_field) { query.selections[1] }
|
76
|
+
|
77
|
+
it "gets name, alias, arguments and directives" do
|
78
|
+
assert_equal "someField", leaf_field.name
|
79
|
+
assert_equal "myField", leaf_field.alias
|
80
|
+
assert_equal 2, leaf_field.directives.length
|
81
|
+
assert_equal 2, leaf_field.arguments.length
|
82
|
+
end
|
83
|
+
|
84
|
+
it "gets nested fields" do
|
85
|
+
assert_equal 2, parent_field.selections.length
|
86
|
+
end
|
87
|
+
|
88
|
+
it "gets location info" do
|
89
|
+
assert_equal [3 ,7], leaf_field.position
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "arguments" do
|
94
|
+
let(:literal_argument) { query.selections.first.arguments.last }
|
95
|
+
let(:variable_argument) { query.selections.first.arguments.first }
|
96
|
+
|
97
|
+
it "gets name and literal value" do
|
98
|
+
assert_equal "ok", literal_argument.name
|
99
|
+
assert_equal 1.4, literal_argument.value
|
100
|
+
end
|
101
|
+
|
102
|
+
it "gets name and variable value" do
|
103
|
+
assert_equal "someArg", variable_argument.name
|
104
|
+
assert_equal "someVar", variable_argument.value.name
|
105
|
+
end
|
106
|
+
|
107
|
+
it "gets position info" do
|
108
|
+
assert_equal [3, 26], variable_argument.position
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "fragment spreads" do
|
113
|
+
let(:fragment_spread) { query.selections[1].selections.last }
|
114
|
+
it "gets the name and directives" do
|
115
|
+
assert_equal "moreNestedFields", fragment_spread.name
|
116
|
+
assert_equal 1, fragment_spread.directives.length
|
117
|
+
end
|
118
|
+
|
119
|
+
it "gets position info" do
|
120
|
+
assert_equal [7, 9], fragment_spread.position
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe "directives" do
|
125
|
+
let(:variable_directive) { query.selections.first.directives.first }
|
126
|
+
|
127
|
+
it "gets the name and arguments" do
|
128
|
+
assert_equal "skip", variable_directive.name
|
129
|
+
assert_equal "if", variable_directive.arguments.first.name
|
130
|
+
assert_equal 1, variable_directive.arguments.length
|
131
|
+
end
|
132
|
+
|
133
|
+
it "gets position info" do
|
134
|
+
assert_equal [3, 54], variable_directive.position
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
describe "inline fragments" do
|
139
|
+
let(:inline_fragment) { query.selections[2] }
|
140
|
+
it "gets the type and directives" do
|
141
|
+
assert_equal "OtherType", inline_fragment.type
|
142
|
+
assert_equal 2, inline_fragment.selections.length
|
143
|
+
assert_equal 1, inline_fragment.directives.length
|
144
|
+
end
|
145
|
+
|
146
|
+
it "gets position info" do
|
147
|
+
assert_equal [10, 7], inline_fragment.position
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
describe "inputs" do
|
152
|
+
let(:query_string) {%|
|
153
|
+
{
|
154
|
+
field(
|
155
|
+
int: 3,
|
156
|
+
float: 4.7e-24,
|
157
|
+
bool: false,
|
158
|
+
string: "☀︎🏆",
|
159
|
+
enum: ENUM_NAME,
|
160
|
+
array: [7, 8, 9]
|
161
|
+
object: {a: [1,2,3], b: {c: "4"}}
|
162
|
+
)
|
163
|
+
}
|
164
|
+
|}
|
165
|
+
|
166
|
+
let(:inputs) { document.definitions.first.selections.first.arguments }
|
167
|
+
|
168
|
+
it "parses ints" do
|
169
|
+
assert_equal 3, inputs[0].value
|
170
|
+
end
|
171
|
+
|
172
|
+
it "parses floats" do
|
173
|
+
assert_equal 0.47e-23, inputs[1].value
|
174
|
+
end
|
175
|
+
|
176
|
+
it "parses booleans" do
|
177
|
+
assert_equal false, inputs[2].value
|
178
|
+
end
|
179
|
+
|
180
|
+
it "parses UTF-8 strings" do
|
181
|
+
assert_equal "☀︎🏆", inputs[3].value
|
182
|
+
end
|
183
|
+
|
184
|
+
it "parses enums" do
|
185
|
+
assert_equal "ENUM_NAME", inputs[4].value
|
186
|
+
end
|
187
|
+
|
188
|
+
it "parses arrays" do
|
189
|
+
assert_equal [7,8,9], inputs[5].value
|
190
|
+
end
|
191
|
+
|
192
|
+
it "parses objects" do
|
193
|
+
obj = inputs[6].value
|
194
|
+
assert_equal "a", obj.arguments[0].name
|
195
|
+
assert_equal [1,2,3], obj.arguments[0].value
|
196
|
+
assert_equal "b", obj.arguments[1].name
|
197
|
+
assert_equal "c", obj.arguments[1].value.arguments[0].name
|
198
|
+
assert_equal "4", obj.arguments[1].value.arguments[0].value
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
describe "unnamed queries" do
|
204
|
+
let(:query_string) {%|
|
205
|
+
{ name, age, height }
|
206
|
+
|}
|
207
|
+
let(:operation) { document.definitions.first }
|
208
|
+
|
209
|
+
it "parses unnamed queries" do
|
210
|
+
assert_equal 1, document.definitions.length
|
211
|
+
assert_equal "query", operation.operation_type
|
212
|
+
assert_equal nil, operation.name
|
213
|
+
assert_equal 3, operation.selections.length
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
describe "introspection query" do
|
218
|
+
let(:query_string) { GraphQL::Introspection::INTROSPECTION_QUERY }
|
219
|
+
it "parses a big ol' query" do
|
220
|
+
assert(document)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
describe "errors" do
|
226
|
+
let(:query_string) {%| query doSomething { bogus { } |}
|
227
|
+
it "raises a parse error" do
|
228
|
+
err = assert_raises(GraphQL::Libgraphqlparser::ParseError) { document }
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,205 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: graphql-libgraphqlparser
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Robert Mosolgo
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-02-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: graphql
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.10.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.10.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: guard
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '2.12'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '2.12'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: guard-bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.1'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2.1'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: guard-minitest
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '2.4'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '2.4'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: guard-rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: minitest
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '5.8'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '5.8'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: minitest-reporters
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '1.0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '1.0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rake
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '10.0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '10.0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: rake-compiler
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0.9'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0.9'
|
153
|
+
description:
|
154
|
+
email:
|
155
|
+
- rdmosolgo@gmail.com
|
156
|
+
executables: []
|
157
|
+
extensions: []
|
158
|
+
extra_rdoc_files: []
|
159
|
+
files:
|
160
|
+
- ".gitignore"
|
161
|
+
- ".travis.yml"
|
162
|
+
- Gemfile
|
163
|
+
- Guardfile
|
164
|
+
- README.md
|
165
|
+
- Rakefile
|
166
|
+
- benchmark.rb
|
167
|
+
- ext/libgraphqlparser/extconf.rb
|
168
|
+
- ext/libgraphqlparser/libgraphqlparser.c
|
169
|
+
- ext/libgraphqlparser/libgraphqlparser.h
|
170
|
+
- ext/libgraphqlparser/visitor_functions.c
|
171
|
+
- ext/libgraphqlparser/visitor_functions.h
|
172
|
+
- graphql-libgraphqlparser.gemspec
|
173
|
+
- lib/graphql/libgraphqlparser.rb
|
174
|
+
- lib/graphql/libgraphqlparser/builder.rb
|
175
|
+
- lib/graphql/libgraphqlparser/monkey_patches/abstract_node.rb
|
176
|
+
- lib/graphql/libgraphqlparser/version.rb
|
177
|
+
- test/graphql/libgraphqlparser_test.rb
|
178
|
+
- test/test_helper.rb
|
179
|
+
homepage: https://github.com/rmosolgo/graphql-libgraphqlparser-ruby
|
180
|
+
licenses:
|
181
|
+
- minitest
|
182
|
+
metadata: {}
|
183
|
+
post_install_message:
|
184
|
+
rdoc_options: []
|
185
|
+
require_paths:
|
186
|
+
- lib
|
187
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
188
|
+
requirements:
|
189
|
+
- - ">="
|
190
|
+
- !ruby/object:Gem::Version
|
191
|
+
version: '0'
|
192
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
193
|
+
requirements:
|
194
|
+
- - ">="
|
195
|
+
- !ruby/object:Gem::Version
|
196
|
+
version: '0'
|
197
|
+
requirements: []
|
198
|
+
rubyforge_project:
|
199
|
+
rubygems_version: 2.2.2
|
200
|
+
signing_key:
|
201
|
+
specification_version: 4
|
202
|
+
summary: Use Libgraphqlparser to parse queries for the GraphQL gem
|
203
|
+
test_files:
|
204
|
+
- test/graphql/libgraphqlparser_test.rb
|
205
|
+
- test/test_helper.rb
|