-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathProgram.cs
244 lines (208 loc) · 7.59 KB
/
Program.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Antlr4.Runtime;
using Antlr4.Runtime.Tree;
using Graph.QL.Parser;
using Newtonsoft.Json.Linq;
namespace Graph.QL
{
public class Resolver : IResolver
{
public void Resolve(IContext typeContext, IObjectType objectType)
{
}
}
public interface IContext
{
JContainer Parent { get; }
ISchema Schema { get; }
}
public interface IResolver
{
void Resolve(IContext typeContext, IObjectType objectType);
}
class Program
{
static void Main(string[] args)
{
if (args == null) throw new ArgumentNullException(nameof(args));
const string q = @"
query HeroNameQuery {
hero {
name
}
}
";
const string s = @"
enum Episode { NEWHOPE, EMPIRE, JEDI }
interface Character {
id: String!
name: String
friends: [Character]
appearsIn: [Episode]
}
type Human implements Character {
id: String!
name: String
friends: [Character]
appearsIn: [Episode]
homePlanet: String
}
type Droid implements Character {
id: String!
name: String
friends: [Character]
appearsIn: [Episode]
primaryFunction: String
}
type Query {
hero(episode: Episode): Character
human(id: String!): Human
droid(id: String!): Droid
}";
StringReader inputStream = new StringReader(s);
AntlrInputStream input = new AntlrInputStream(inputStream.ReadToEnd());
GraphQLSchemaLexer lexer = new GraphQLSchemaLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
GraphQLSchemaParser parser = new GraphQLSchemaParser(tokens);
var documentContext = parser.document();
Console.WriteLine(documentContext.ToStringTree());
ISchema schema = new GraphQLSchemaVisitor().Visit(documentContext);
ParseQuery(schema, q);
}
static void ParseQuery(ISchema schema, string s)
{
var query = schema.getType("Query");
StringReader inputStream = new StringReader(s);
AntlrInputStream input = new AntlrInputStream(inputStream.ReadToEnd());
GraphQLLexer lexer = new GraphQLLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
GraphQLParser parser = new GraphQLParser(tokens);
var documentContext = parser.document();
new GraphQLVisitor(schema).Visit(documentContext);
}
}
public class GraphQLVisitor : GraphQLBaseVisitor<IContext>
{
readonly ISchema _schema;
IResolver _resolver;
Context _context;
public GraphQLVisitor(ISchema schema)
{
_schema = schema;
_resolver = new Resolver();
_context = new Context(_schema);
}
public override IContext VisitOperationDefinition(GraphQLParser.OperationDefinitionContext context)
{
var operationType = context.operationType().GetText();
if(operationType == "query")
{
var typeName = context.NAME().GetText();
_context.Push(typeName);
var type = _schema.getType(typeName);
_resolver.Resolve(_context, type as IObjectType);
_context.Pop();
return _context;
}
return _context;
}
private class Context : IContext
{
public Context(ISchema schema)
{
Parent = new JObject();
Root = new JObject {["Data"] = Parent};
Schema = schema;
}
public void Push(string name)
{
var newParent = new JObject();
Parent[name] = newParent;
Parent = newParent;
}
public void Pop()
{
Parent = Parent.Parent;
}
private JContainer Root { get; set; }
public JContainer Parent { get; private set; }
public ISchema Schema { get; }
}
}
public class GraphQLSchemaVisitor : GraphQLSchemaBaseVisitor<ISchema>
{
readonly Schema _schema;
InterfaceType _currentType;
public GraphQLSchemaVisitor()
{
_schema = new Schema();
_currentType = null;
}
public override ISchema Visit(IParseTree tree)
{
base.Visit(tree);
return _schema;
}
public override ISchema VisitField(GraphQLSchemaParser.FieldContext context)
{
string fieldName = context.NAME().ToString();
var typeContext = context.fieldDefinition().type();
var typeInfo = this.getType(typeContext);
var argumentsContext = context.arguments();
if (argumentsContext == null)
{
var isRequired = typeContext.nonNullType() != null;
_currentType.add(new Property(fieldName, typeInfo, isRequired));
return _schema;
}
List<IParameter> parameters = new List<IParameter>();
foreach (var argumentContext in argumentsContext.argument())
{
var parameterName = argumentContext.NAME().ToString();
var parameterType = this.getType(argumentContext.type());
var isRequired = argumentContext.type().nonNullType() != null;
parameters.Add(new Parameter(parameterName, parameterType, isRequired));
}
_currentType.add(new Method(fieldName, typeInfo, parameters));
return _schema;
}
public IType getType(GraphQLSchemaParser.TypeContext typeContext)
{
var typeNameContext = typeContext.typeName();
if (typeNameContext != null)
return _schema.getType(typeNameContext.NAME().ToString());
var listTypeContext = typeContext.listType();
if (listTypeContext == null)
return null;
IType typeInfo = getType(listTypeContext.type());
return new ListType("list", typeInfo);
}
public override ISchema VisitEnumDefinition(GraphQLSchemaParser.EnumDefinitionContext context)
{
var typeName = context.NAME().ToString();
var typeInfo = new EnumType(typeName);
foreach (var e in context.enumBodyDefinition().NAME())
{
typeInfo.add(new Property(e.ToString(), ScalarType.String, false));
}
_schema.add(typeInfo);
return _schema;
}
public override ISchema VisitTypeDefinition(GraphQLSchemaParser.TypeDefinitionContext context)
{
_currentType = new ObjectType(context.NAME().ToString());
_schema.add(_currentType);
return base.VisitTypeDefinition(context);
}
public override ISchema VisitInterfaceDefinition(GraphQLSchemaParser.InterfaceDefinitionContext context)
{
_currentType = new InterfaceType(context.NAME().ToString());
_schema.add(_currentType);
return base.VisitInterfaceDefinition(context);
}
}
}