agoo 2.5.7 → 2.6.0

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.

Potentially problematic release.


This version of agoo might be problematic. Click here for more details.

Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/README.md +38 -0
  4. data/ext/agoo/agoo.c +11 -2
  5. data/ext/agoo/bind.c +15 -20
  6. data/ext/agoo/con.c +32 -25
  7. data/ext/agoo/debug.c +225 -162
  8. data/ext/agoo/debug.h +31 -51
  9. data/ext/agoo/doc.c +278 -5
  10. data/ext/agoo/doc.h +6 -1
  11. data/ext/agoo/err.c +1 -0
  12. data/ext/agoo/err.h +1 -0
  13. data/ext/agoo/error_stream.c +3 -6
  14. data/ext/agoo/gqlcobj.c +12 -0
  15. data/ext/agoo/gqlcobj.h +25 -0
  16. data/ext/agoo/gqleval.c +520 -0
  17. data/ext/agoo/gqleval.h +49 -0
  18. data/ext/agoo/gqlintro.c +1237 -97
  19. data/ext/agoo/gqlintro.h +8 -0
  20. data/ext/agoo/gqljson.c +460 -0
  21. data/ext/agoo/gqljson.h +15 -0
  22. data/ext/agoo/gqlvalue.c +679 -136
  23. data/ext/agoo/gqlvalue.h +29 -7
  24. data/ext/agoo/graphql.c +841 -362
  25. data/ext/agoo/graphql.h +180 -90
  26. data/ext/agoo/hook.c +8 -16
  27. data/ext/agoo/http.c +3 -4
  28. data/ext/agoo/log.c +22 -25
  29. data/ext/agoo/log.h +1 -0
  30. data/ext/agoo/page.c +24 -40
  31. data/ext/agoo/pub.c +23 -21
  32. data/ext/agoo/queue.c +2 -4
  33. data/ext/agoo/ready.c +9 -9
  34. data/ext/agoo/req.c +80 -5
  35. data/ext/agoo/req.h +2 -0
  36. data/ext/agoo/res.c +1 -3
  37. data/ext/agoo/rgraphql.c +753 -0
  38. data/ext/agoo/rresponse.c +9 -15
  39. data/ext/agoo/rserver.c +18 -17
  40. data/ext/agoo/sdl.c +1264 -120
  41. data/ext/agoo/sdl.h +8 -1
  42. data/ext/agoo/sectime.c +136 -0
  43. data/ext/agoo/sectime.h +19 -0
  44. data/ext/agoo/server.c +1 -3
  45. data/ext/agoo/subject.c +2 -4
  46. data/ext/agoo/text.c +124 -18
  47. data/ext/agoo/text.h +5 -1
  48. data/ext/agoo/upgraded.c +2 -4
  49. data/lib/agoo/version.rb +1 -1
  50. data/test/base_handler_test.rb +43 -40
  51. data/test/bind_test.rb +49 -48
  52. data/test/graphql_test.rb +1019 -0
  53. data/test/hijack_test.rb +1 -1
  54. data/test/rack_handler_test.rb +40 -34
  55. data/test/static_test.rb +33 -32
  56. metadata +17 -6
@@ -0,0 +1,49 @@
1
+ // Copyright (c) 2018, Peter Ohler, All rights reserved.
2
+
3
+ #ifndef AGOO_GQLEVAL_H
4
+ #define AGOO_GQLEVAL_H
5
+
6
+ #include <stdbool.h>
7
+
8
+ #include "err.h"
9
+
10
+ // Used for references to implemenation entities.
11
+ typedef void* gqlRef;
12
+
13
+ typedef struct _gqlKeyVal {
14
+ const char *key;
15
+ struct _gqlValue *value;
16
+ } *gqlKeyVal;
17
+
18
+ struct _gqlDoc;
19
+ struct _gqlField;
20
+ struct _gqlSel;
21
+ struct _gqlType;
22
+ struct _gqlValue;
23
+
24
+ // Resolve field on a target to a child reference.
25
+ typedef int (*gqlResolveFunc)(agooErr err,
26
+ struct _gqlDoc *doc,
27
+ gqlRef target,
28
+ struct _gqlField *field,
29
+ struct _gqlSel *sel,
30
+ struct _gqlValue *result,
31
+ int depth);
32
+
33
+ // Determine the type of a reference. Return NULL if can't be determined.
34
+ typedef struct _gqlType* (*gqlTypeFunc)(gqlRef ref);
35
+
36
+
37
+ extern struct _gqlValue* gql_doc_eval(agooErr err, struct _gqlDoc *doc);
38
+ extern struct _gqlValue* gql_get_arg_value(gqlKeyVal args, const char *key);
39
+ extern int gql_eval_sels(agooErr err, struct _gqlDoc *doc, gqlRef ref, struct _gqlField *field, struct _gqlSel *sels, struct _gqlValue *result, int depth);
40
+ extern int gql_set_typename(agooErr err, struct _gqlType *type, const char *key, struct _gqlValue *result);
41
+
42
+ extern gqlRef gql_root;
43
+ extern gqlResolveFunc gql_resolve_func;
44
+ extern gqlTypeFunc gql_type_func;
45
+ extern gqlRef (*gql_root_op)(const char *op);
46
+
47
+ extern struct _gqlValue* (*gql_doc_eval_func)(agooErr err, struct _gqlDoc *doc);
48
+
49
+ #endif // AGOO_GQLEVAL_H
@@ -1,21 +1,15 @@
1
1
  // Copyright (c) 2018, Peter Ohler, All rights reserved.
2
2
 
3
+ #include <stdio.h>
3
4
  #include <stdlib.h>
4
5
  #include <string.h>
5
6
 
7
+ #include "debug.h"
8
+ #include "gqlcobj.h"
6
9
  #include "gqlintro.h"
7
10
  #include "gqlvalue.h"
8
11
  #include "graphql.h"
9
12
 
10
- static gqlType schema_type;
11
- static gqlType type_type;
12
- static gqlType type_kind_type;
13
- static gqlType field_type;
14
- static gqlType input_value_type;
15
- static gqlType enum_value_type;
16
- static gqlType directive_type;
17
- static gqlType directive_location_type;
18
-
19
13
  // type __Schema {
20
14
  // types: [__Type!]!
21
15
  // queryType: __Type!
@@ -23,33 +17,30 @@ static gqlType directive_location_type;
23
17
  // subscriptionType: __Type
24
18
  // directives: [__Directive!]!
25
19
  // }
26
- static gqlRef
27
- schema_types_resolve(gqlRef target, const char *fieldName, gqlKeyVal *args) {
28
- // TBD
29
- return NULL;
30
- }
31
-
32
- static gqlRef
33
- schema_query_type_resolve(gqlRef target, const char *fieldName, gqlKeyVal *args) {
34
- // TBD return schema_type.query.type
35
- // lookup "schema" type
36
- // get query field
37
- // get return type of field
38
- return NULL;
39
- }
40
-
41
20
  static int
42
21
  create_schema_type(agooErr err) {
43
- if (NULL == (schema_type = gql_type_create(err, "__Schema", NULL, -1, true, NULL)) ||
44
- NULL == gql_type_field(err, schema_type, "types", type_type, NULL, true, true, true, schema_types_resolve) ||
45
- NULL == gql_type_field(err, schema_type, "queryType", type_type, NULL, true, false, false, schema_query_type_resolve) ||
46
- NULL == gql_type_field(err, schema_type, "mutationType", type_type, NULL, false, false, false, NULL) ||
47
- NULL == gql_type_field(err, schema_type, "subscriptionType", type_type, NULL, false, false, false, NULL) ||
48
- NULL == gql_type_field(err, schema_type, "directives", directive_type, NULL, true, true, true, NULL)) {
22
+ gqlType type;
23
+ gqlType type_type;
24
+ gqlType type_list;
25
+ gqlType dir_type;
26
+ gqlType dir_list;
27
+
28
+ if (NULL == (type = gql_type_create(err, "__Schema", NULL, 0, NULL)) ||
29
+
30
+ NULL == (type_type = gql_assure_type(err, "__Type")) ||
31
+ NULL == (type_list = gql_assure_list(err, type_type, true)) ||
32
+ NULL == (dir_type = gql_assure_type(err, "__Directive")) ||
33
+ NULL == (dir_list = gql_assure_list(err, dir_type, true)) ||
34
+
35
+ NULL == gql_type_field(err, type, "types", type_list, NULL, NULL, 0, true) ||
36
+ NULL == gql_type_field(err, type, "queryType", type_type, NULL, NULL, 0, true) ||
37
+ NULL == gql_type_field(err, type, "mutationType", type_type, NULL, NULL, 0, false) ||
38
+ NULL == gql_type_field(err, type, "subscriptionType", type_type, NULL, NULL, 0, false) ||
39
+ NULL == gql_type_field(err, type, "directives", dir_list, NULL, NULL, 0, true)) {
49
40
 
50
41
  return err->code;
51
42
  }
52
- schema_type->core = true;
43
+ type->core = true;
53
44
 
54
45
  return AGOO_ERR_OK;
55
46
  }
@@ -67,29 +58,49 @@ create_schema_type(agooErr err) {
67
58
  // }
68
59
  static int
69
60
  create_type_type(agooErr err) {
61
+ gqlType type;
70
62
  gqlField fields = NULL;
71
63
  gqlField enum_values = NULL;
72
64
  gqlValue dv;
65
+ gqlType kind_type;
66
+ gqlType type_list;
67
+ gqlType field_type;
68
+ gqlType field_list;
69
+ gqlType enum_type;
70
+ gqlType enum_list;
71
+ gqlType input_type;
72
+ gqlType input_list;
73
73
 
74
- if (NULL == (type_type = gql_type_create(err, "__Type", NULL, -1, true, NULL)) ||
75
- NULL == gql_type_field(err, type_type, "kind", type_kind_type, NULL, true, false, false, NULL) ||
76
- NULL == gql_type_field(err, type_type, "name", &gql_string_type, NULL, false, false, false, NULL) ||
77
- NULL == gql_type_field(err, type_type, "description", &gql_string_type, NULL, false, false, false, NULL) ||
78
- NULL == (fields = gql_type_field(err, type_type, "fields", field_type, NULL, false, true, true, NULL)) ||
79
- NULL == gql_type_field(err, type_type, "interfaces", type_type, NULL, false, true, true, NULL) ||
80
- NULL == gql_type_field(err, type_type, "possibleTypes", type_type, NULL, false, true, true, NULL) ||
81
- NULL == (enum_values = gql_type_field(err, type_type, "enumValues", enum_value_type, NULL, false, true, true, NULL)) ||
82
- NULL == gql_type_field(err, type_type, "inputFields", input_value_type, NULL, false, true, true, NULL) ||
83
- NULL == gql_type_field(err, type_type, "ofType", type_type, NULL, false, false, false, NULL)) {
74
+ if (NULL == (type = gql_type_create(err, "__Type", NULL, 0, NULL)) ||
75
+
76
+ NULL == (type_list = gql_assure_list(err, type, true)) ||
77
+ NULL == (field_type = gql_assure_type(err, "__Field")) ||
78
+ NULL == (field_list = gql_assure_list(err, field_type, true)) ||
79
+ NULL == (kind_type = gql_assure_type(err, "__TypeKind")) ||
80
+ NULL == (enum_type = gql_assure_type(err, "__EnumValue")) ||
81
+ NULL == (enum_list = gql_assure_list(err, enum_type, true)) ||
82
+ NULL == (input_type = gql_assure_type(err, "__InputValue")) ||
83
+ NULL == (input_list = gql_assure_list(err, input_type, true)) ||
84
+
85
+ NULL == gql_type_field(err, type, "kind", kind_type, NULL, NULL, 0, true) ||
86
+ NULL == gql_type_field(err, type, "name", &gql_string_type, NULL, NULL, 0, false) ||
87
+ NULL == gql_type_field(err, type, "description", &gql_string_type, NULL, NULL, 0, false) ||
88
+ NULL == (fields = gql_type_field(err, type, "fields", field_list, NULL, NULL, 0, false)) ||
89
+ NULL == gql_type_field(err, type, "interfaces", type_list, NULL, NULL, 0, false) ||
90
+ NULL == gql_type_field(err, type, "possibleTypes", type_list, NULL, NULL, 0, false) ||
91
+ NULL == (enum_values = gql_type_field(err, type, "enumValues", enum_list, NULL, NULL, 0, false)) ||
92
+ NULL == gql_type_field(err, type, "inputFields", input_list, NULL, NULL, 0, false) ||
93
+ NULL == gql_type_field(err, type, "ofType", type, NULL, NULL, 0, false)) {
84
94
 
85
95
  return err->code;
86
96
  }
87
- type_type->core = true;
97
+ type->core = true;
88
98
 
89
99
  if (NULL == (dv = gql_bool_create(err, false)) ||
90
- NULL == gql_field_arg(err, fields, "includeDeprecated", &gql_bool_type, NULL, dv, false) ||
100
+
101
+ NULL == gql_field_arg(err, fields, "includeDeprecated", &gql_bool_type, NULL, 0, dv, false) ||
91
102
  NULL == (dv = gql_bool_create(err, false)) ||
92
- NULL == gql_field_arg(err, enum_values, "includeDeprecated", &gql_bool_type, NULL, dv, false)) {
103
+ NULL == gql_field_arg(err, enum_values, "includeDeprecated", &gql_bool_type, NULL, 0, dv, false)) {
93
104
 
94
105
  return err->code;
95
106
  }
@@ -110,11 +121,15 @@ create_type_kind_type(agooErr err) {
110
121
  NULL
111
122
  };
112
123
  const char **cp;
113
-
114
- type_kind_type = gql_enum_create(err, "__TypeKind", NULL, -1, true);
115
- type_kind_type->core = true;
124
+ gqlType type;
125
+
126
+ if (NULL == (type = gql_enum_create(err, "__TypeKind", NULL, 0))) {
127
+ return err->code;
128
+ }
129
+ type->core = true;
130
+
116
131
  for (cp = choices; NULL != *cp; cp++) {
117
- if (AGOO_ERR_OK != gql_enum_append(err, type_kind_type, *cp, -1)) {
132
+ if (NULL == gql_enum_append(err, type, *cp, 0, NULL, 0)) {
118
133
  return err->code;
119
134
  }
120
135
  }
@@ -131,17 +146,27 @@ create_type_kind_type(agooErr err) {
131
146
  // }
132
147
  static int
133
148
  create_field_type(agooErr err) {
134
- if (NULL == (field_type = gql_type_create(err, "__Field", NULL, -1, true, NULL)) ||
135
- NULL == gql_type_field(err, field_type, "name", &gql_string_type, NULL, true, false, false, NULL) ||
136
- NULL == gql_type_field(err, field_type, "description", &gql_string_type, NULL, false, false, false, NULL) ||
137
- NULL == gql_type_field(err, field_type, "args", input_value_type, NULL, true, true, true, NULL) ||
138
- NULL == gql_type_field(err, field_type, "type", type_type, NULL, true, false, false, NULL) ||
139
- NULL == gql_type_field(err, field_type, "isDeprecated", &gql_bool_type, NULL, true, false, false, NULL) ||
140
- NULL == gql_type_field(err, field_type, "reason", &gql_string_type, NULL, false, false, false, NULL)) {
149
+ gqlType type;
150
+ gqlType type_type;
151
+ gqlType input_type;
152
+ gqlType input_list;
153
+
154
+ if (NULL == (type = gql_type_create(err, "__Field", NULL, 0, NULL)) ||
155
+
156
+ NULL == (type_type = gql_assure_type(err, "__Type")) ||
157
+ NULL == (input_type = gql_assure_type(err, "__InputValue")) ||
158
+ NULL == (input_list = gql_assure_list(err, input_type, true)) ||
159
+
160
+ NULL == gql_type_field(err, type, "name", &gql_string_type, NULL, NULL, 0, true) ||
161
+ NULL == gql_type_field(err, type, "description", &gql_string_type, NULL, NULL, 0, false) ||
162
+ NULL == gql_type_field(err, type, "args", input_list, NULL, NULL, 0, true) ||
163
+ NULL == gql_type_field(err, type, "type", type_type, NULL, NULL, 0, true) ||
164
+ NULL == gql_type_field(err, type, "isDeprecated", &gql_bool_type, NULL, NULL, 0, true) ||
165
+ NULL == gql_type_field(err, type, "reason", &gql_string_type, NULL, NULL, 0, false)) {
141
166
 
142
167
  return err->code;
143
168
  }
144
- field_type->core = true;
169
+ type->core = true;
145
170
 
146
171
  return AGOO_ERR_OK;
147
172
  }
@@ -154,15 +179,21 @@ create_field_type(agooErr err) {
154
179
  // }
155
180
  static int
156
181
  create_input_type(agooErr err) {
157
- if (NULL == (input_value_type = gql_type_create(err, "__InputValue", NULL, -1, true, NULL)) ||
158
- NULL == gql_type_field(err, input_value_type, "name", &gql_string_type, NULL, true, false, false, NULL) ||
159
- NULL == gql_type_field(err, input_value_type, "description", &gql_string_type, NULL, false, false, false, NULL) ||
160
- NULL == gql_type_field(err, input_value_type, "type", type_type, NULL, true, false, false, NULL) ||
161
- NULL == gql_type_field(err, input_value_type, "defaultValue", &gql_string_type, NULL, false, false, false, NULL)) {
182
+ gqlType type;
183
+ gqlType type_type;
184
+
185
+ if (NULL == (type = gql_type_create(err, "__InputValue", NULL, 0, NULL)) ||
186
+
187
+ NULL == (type_type = gql_assure_type(err, "__Type")) ||
188
+
189
+ NULL == gql_type_field(err, type, "name", &gql_string_type, NULL, NULL, 0, true) ||
190
+ NULL == gql_type_field(err, type, "description", &gql_string_type, NULL, NULL, 0, false) ||
191
+ NULL == gql_type_field(err, type, "type", type_type, NULL, NULL, 0, true) ||
192
+ NULL == gql_type_field(err, type, "defaultValue", &gql_string_type, NULL, NULL, 0, false)) {
162
193
 
163
194
  return err->code;
164
195
  }
165
- input_value_type->core = true;
196
+ type->core = true;
166
197
 
167
198
  return AGOO_ERR_OK;
168
199
  }
@@ -175,15 +206,17 @@ create_input_type(agooErr err) {
175
206
  // }
176
207
  static int
177
208
  create_enum_type(agooErr err) {
178
- if (NULL == (enum_value_type = gql_type_create(err, "__EnumValue", NULL, -1, true, NULL)) ||
179
- NULL == gql_type_field(err, enum_value_type, "name", &gql_string_type, NULL, true, false, false, NULL) ||
180
- NULL == gql_type_field(err, enum_value_type, "description", &gql_string_type, NULL, false, false, false, NULL) ||
181
- NULL == gql_type_field(err, enum_value_type, "isDeprecated", &gql_bool_type, NULL, true, false, false, NULL) ||
182
- NULL == gql_type_field(err, enum_value_type, "deprecationReason", &gql_string_type, NULL, false, false, false, NULL)) {
209
+ gqlType type;
210
+
211
+ if (NULL == (type = gql_type_create(err, "__EnumValue", NULL, 0, NULL)) ||
212
+ NULL == gql_type_field(err, type, "name", &gql_string_type, NULL, NULL, 0, true) ||
213
+ NULL == gql_type_field(err, type, "description", &gql_string_type, NULL, NULL, 0, false) ||
214
+ NULL == gql_type_field(err, type, "isDeprecated", &gql_bool_type, NULL, NULL, 0, true) ||
215
+ NULL == gql_type_field(err, type, "deprecationReason", &gql_string_type, NULL, NULL, 0, false)) {
183
216
 
184
217
  return err->code;
185
218
  }
186
- enum_value_type->core = true;
219
+ type->core = true;
187
220
 
188
221
  return AGOO_ERR_OK;
189
222
  }
@@ -196,15 +229,27 @@ create_enum_type(agooErr err) {
196
229
  // }
197
230
  static int
198
231
  create_directive_type(agooErr err) {
199
- if (NULL == (directive_type = gql_type_create(err, "__Directive", NULL, -1, true, NULL)) ||
200
- NULL == gql_type_field(err, directive_type, "name", &gql_string_type, NULL, true, false, false, NULL) ||
201
- NULL == gql_type_field(err, directive_type, "description", &gql_string_type, NULL, false, false, false, NULL) ||
202
- NULL == gql_type_field(err, directive_type, "location", directive_location_type, NULL, true, true, true, NULL) ||
203
- NULL == gql_type_field(err, directive_type, "args", input_value_type, NULL, true, true, true, NULL)) {
232
+ gqlType type;
233
+ gqlType input_type;
234
+ gqlType input_list;
235
+ gqlType loc_type;
236
+ gqlType loc_list;
237
+
238
+ if (NULL == (type = gql_type_create(err, "__Directive", NULL, 0, NULL)) ||
239
+
240
+ NULL == (input_type = gql_assure_type(err, "__InputValue")) ||
241
+ NULL == (input_list = gql_assure_list(err, input_type, true)) ||
242
+ NULL == (loc_type = gql_assure_type(err, "__DirectiveLocation")) ||
243
+ NULL == (loc_list = gql_assure_list(err, loc_type, true)) ||
244
+
245
+ NULL == gql_type_field(err, type, "name", &gql_string_type, NULL, NULL, 0, true) ||
246
+ NULL == gql_type_field(err, type, "description", &gql_string_type, NULL, NULL, 0, false) ||
247
+ NULL == gql_type_field(err, type, "locations", loc_list, NULL, NULL, 0, true) ||
248
+ NULL == gql_type_field(err, type, "args", input_list, NULL, NULL, 0, true)) {
204
249
 
205
250
  return err->code;
206
251
  }
207
- directive_type->core = true;
252
+ type->core = true;
208
253
 
209
254
  return AGOO_ERR_OK;
210
255
  }
@@ -232,11 +277,14 @@ create_directive_location_type(agooErr err) {
232
277
  "INPUT_FIELD_DEFINITION",
233
278
  NULL };
234
279
  const char **cp;
280
+ gqlType type;
235
281
 
236
- directive_location_type = gql_enum_create(err, "__DirectiveLocation", NULL, -1, true);
237
- directive_location_type->core = true;
282
+ if (NULL == (type = gql_enum_create(err, "__DirectiveLocation", NULL, 0))) {
283
+ return err->code;
284
+ }
285
+ type->core = true;
238
286
  for (cp = choices; NULL != *cp; cp++) {
239
- if (AGOO_ERR_OK != gql_enum_append(err, directive_location_type, *cp, -1)) {
287
+ if (NULL == gql_enum_append(err, type, *cp, 0, NULL, 0)) {
240
288
  return err->code;
241
289
  }
242
290
  }
@@ -245,15 +293,16 @@ create_directive_location_type(agooErr err) {
245
293
 
246
294
  static int
247
295
  create_dir_skip(agooErr err) {
248
- gqlDir dir = gql_directive_create(err, "skip", NULL, -1, true);
296
+ gqlDir dir = gql_directive_create(err, "skip", NULL, 0);
249
297
 
250
298
  if (NULL == dir) {
251
299
  return err->code;
252
300
  }
301
+ dir->core = true;
253
302
  if (AGOO_ERR_OK != gql_directive_on(err, dir, "FIELD", -1) ||
254
303
  AGOO_ERR_OK != gql_directive_on(err, dir, "FRAGMENT_SPREAD", -1) ||
255
304
  AGOO_ERR_OK != gql_directive_on(err, dir, "INLINE_FRAGMENT", -1) ||
256
- NULL == gql_dir_arg(err, dir, "if", "Boolean", NULL, -1, NULL, true)) {
305
+ NULL == gql_dir_arg(err, dir, "if", &gql_bool_type, NULL, -1, NULL, true)) {
257
306
 
258
307
  return err->code;
259
308
  }
@@ -262,15 +311,16 @@ create_dir_skip(agooErr err) {
262
311
 
263
312
  static int
264
313
  create_dir_include(agooErr err) {
265
- gqlDir dir = gql_directive_create(err, "include", NULL, -1, true);
314
+ gqlDir dir = gql_directive_create(err, "include", NULL, 0);
266
315
 
267
316
  if (NULL == dir) {
268
317
  return err->code;
269
318
  }
319
+ dir->core = true;
270
320
  if (AGOO_ERR_OK != gql_directive_on(err, dir, "FIELD", -1) ||
271
321
  AGOO_ERR_OK != gql_directive_on(err, dir, "FRAGMENT_SPREAD", -1) ||
272
322
  AGOO_ERR_OK != gql_directive_on(err, dir, "INLINE_FRAGMENT", -1) ||
273
- NULL == gql_dir_arg(err, dir, "if", "Boolean", NULL, -1, NULL, true)) {
323
+ NULL == gql_dir_arg(err, dir, "if", &gql_bool_type, NULL, 0, NULL, true)) {
274
324
 
275
325
  return err->code;
276
326
  }
@@ -279,16 +329,17 @@ create_dir_include(agooErr err) {
279
329
 
280
330
  static int
281
331
  create_dir_deprecated(agooErr err) {
282
- gqlDir dir = gql_directive_create(err, "deprecated", NULL, -1, true);
332
+ gqlDir dir = gql_directive_create(err, "deprecated", NULL, 0);
283
333
  gqlValue dv;
284
334
 
285
335
  if (NULL == dir) {
286
336
  return err->code;
287
337
  }
338
+ dir->core = true;
288
339
  if (AGOO_ERR_OK != gql_directive_on(err, dir, "FIELD_DEFINITION", -1) ||
289
340
  AGOO_ERR_OK != gql_directive_on(err, dir, "ENUM_VALUE", -1) ||
290
341
  NULL == (dv = gql_string_create(err, "No longer supported", -1)) ||
291
- NULL == gql_dir_arg(err, dir, "reason", "String", NULL, -1, dv, false)) {
342
+ NULL == gql_dir_arg(err, dir, "reason", &gql_string_type, NULL, -1, dv, false)) {
292
343
 
293
344
  return err->code;
294
345
  }
@@ -297,8 +348,6 @@ create_dir_deprecated(agooErr err) {
297
348
 
298
349
  int
299
350
  gql_intro_init(agooErr err) {
300
- gqlField f;
301
-
302
351
  if (AGOO_ERR_OK != create_type_kind_type(err) ||
303
352
  AGOO_ERR_OK != create_input_type(err) ||
304
353
  AGOO_ERR_OK != create_type_type(err) ||
@@ -313,21 +362,1112 @@ gql_intro_init(agooErr err) {
313
362
 
314
363
  return err->code;
315
364
  }
316
- // InputValue and Type as well Field and Type as have a depency loop so
317
- // complete the loop.
318
- for (f = input_value_type->fields; NULL != f; f = f->next) {
319
- if (0 == strcmp("type", f->name)) {
320
- f->type = type_type;
321
- break;
365
+ return AGOO_ERR_OK;
366
+ }
367
+
368
+ // introspection handlers /////////////////////////////////////////////////////////////////////
369
+
370
+ static struct _gqlCclass type_class;
371
+
372
+ static gqlValue
373
+ extract_arg(agooErr err, gqlField field, gqlSel sel, const char *key) {
374
+ if (NULL != sel->args) {
375
+ gqlSelArg sa;
376
+ gqlValue v = NULL;
377
+
378
+ for (sa = sel->args; NULL != sa; sa = sa->next) {
379
+ if (0 != strcmp(sa->name, key)) {
380
+ continue;
381
+ }
382
+ if (NULL != sa->var) {
383
+ v = sa->var->value;
384
+ } else {
385
+ v = sa->value;
386
+ }
387
+ if (NULL != field) {
388
+ gqlArg fa;
389
+
390
+ for (fa = field->args; NULL != fa; fa = fa->next) {
391
+ if (0 == strcmp(sa->name, fa->name)) {
392
+ if (v->type != fa->type && GQL_SCALAR_VAR != v->type->scalar_kind) {
393
+ if (AGOO_ERR_OK != gql_value_convert(err, v, fa->type)) {
394
+ return NULL;
395
+ }
396
+ }
397
+ break;
398
+ }
399
+ }
400
+ }
401
+ }
402
+ return v;
403
+ }
404
+ return NULL;
405
+ }
406
+
407
+ static bool
408
+ is_deprecated(gqlDirUse use) {
409
+ for (; NULL != use; use = use->next) {
410
+ if (0 == strcmp("deprecated", use->dir->name)) {
411
+ return true;
412
+ }
413
+ }
414
+ return false;
415
+ }
416
+
417
+ static const char*
418
+ deprecation_reason(gqlDirUse use) {
419
+ const char *reason = NULL;
420
+
421
+ for (; NULL != use; use = use->next) {
422
+ if (0 == strcmp("deprecated", use->dir->name)) {
423
+ gqlLink a;
424
+
425
+ for (a = use->args; NULL != a; a = a->next) {
426
+ if (0 == strcmp("reason", a->key)) {
427
+ reason = gql_string_get(a->value);
428
+ break;
429
+ }
430
+ }
431
+ }
432
+ }
433
+ return reason;
434
+ }
435
+
436
+ // InputValue
437
+ // name: String!
438
+ static int
439
+ input_value_name(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
440
+ const char *key = sel->name;
441
+
442
+ if (NULL != sel->alias) {
443
+ key = sel->alias;
444
+ }
445
+ return gql_object_set(err, result, key, gql_string_create(err, ((gqlArg)obj->ptr)->name, -1));
446
+ }
447
+
448
+ // description: String
449
+ static int
450
+ input_value_description(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
451
+ const char *key = sel->name;
452
+ const char *s = ((gqlArg)obj->ptr)->desc;
453
+ gqlValue desc;
454
+
455
+ if (NULL != sel->alias) {
456
+ key = sel->alias;
457
+ }
458
+ if (NULL == s) {
459
+ desc = gql_null_create(err);
460
+ } else {
461
+ desc = gql_string_create(err, s, -1);
462
+ }
463
+ return gql_object_set(err, result, key, desc);
464
+ }
465
+
466
+ // type: __Type!
467
+ static int
468
+ input_value_type(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
469
+ gqlArg a = (gqlArg)obj->ptr;
470
+ const char *key = sel->name;
471
+ struct _gqlCobj child = { .clas = &type_class };
472
+ gqlValue co;
473
+
474
+ if (NULL != sel->alias) {
475
+ key = sel->alias;
476
+ }
477
+ if (NULL == a || NULL == a->type) {
478
+ return gql_object_set(err, result, key, gql_null_create(err));
479
+ }
480
+ if (NULL == (co = gql_object_create(err)) ||
481
+ AGOO_ERR_OK != gql_object_set(err, result, key, co)) {
482
+ return err->code;
483
+ }
484
+ child.ptr = (void*)a->type;
485
+
486
+ return gql_eval_sels(err, doc, (gqlRef)&child, field, sel->sels, co, depth + 1);
487
+ }
488
+
489
+ // defaultValue: String
490
+ static int
491
+ input_value_default_value(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
492
+ gqlArg a = (gqlArg)obj->ptr;
493
+ const char *key = sel->name;
494
+ gqlValue dv = a->default_value;
495
+
496
+ if (NULL != sel->alias) {
497
+ key = sel->alias;
498
+ }
499
+ if (NULL == dv) {
500
+ return gql_object_set(err, result, key, gql_null_create(err));
501
+ }
502
+ if (NULL == (dv = gql_value_dup(err, dv))) {
503
+ return err->code;
504
+ }
505
+ if (AGOO_ERR_OK != gql_value_convert(err, dv, &gql_string_type)) {
506
+ return err->code;
507
+ }
508
+ return gql_object_set(err, result, key, dv);
509
+ }
510
+
511
+ static struct _gqlCmethod input_value_methods[] = {
512
+ { .key = "name", .func = input_value_name },
513
+ { .key = "description", .func = input_value_description },
514
+ { .key = "type", .func = input_value_type },
515
+ { .key = "defaultValue", .func = input_value_default_value },
516
+ { .key = NULL, .func = NULL },
517
+ };
518
+
519
+ static struct _gqlCclass input_value_class = {
520
+ .name = "__InputValue",
521
+ .methods = input_value_methods,
522
+ };
523
+
524
+ // __Field
525
+ // name: String!
526
+ static int
527
+ field_name(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
528
+ const char *key = sel->name;
529
+
530
+ if (NULL != sel->alias) {
531
+ key = sel->alias;
532
+ }
533
+ return gql_object_set(err, result, key, gql_string_create(err, ((gqlField)obj->ptr)->name, -1));
534
+ }
535
+
536
+ // description: String
537
+ static int
538
+ field_description(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
539
+ const char *key = sel->name;
540
+ const char *s = ((gqlField)obj->ptr)->desc;
541
+ gqlValue desc;
542
+
543
+ if (NULL != sel->alias) {
544
+ key = sel->alias;
545
+ }
546
+ if (NULL == s) {
547
+ desc = gql_null_create(err);
548
+ } else {
549
+ desc = gql_string_create(err, s, -1);
550
+ }
551
+ return gql_object_set(err, result, key, desc);
552
+ }
553
+
554
+ // args: [__InputValue!]!
555
+ static int
556
+ field_args(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
557
+ gqlField f = (gqlField)obj->ptr;
558
+ const char *key = sel->name;
559
+ gqlArg a;
560
+ gqlValue list = gql_list_create(err, NULL);
561
+ gqlValue co;
562
+ struct _gqlField cf;
563
+ struct _gqlCobj child = { .clas = &input_value_class };
564
+ int d2 = depth + 1;
565
+
566
+ if (NULL != sel->alias) {
567
+ key = sel->alias;
568
+ }
569
+ if (NULL == list ||
570
+ AGOO_ERR_OK != gql_object_set(err, result, key, list)) {
571
+ return err->code;
572
+ }
573
+ memset(&cf, 0, sizeof(cf));
574
+ cf.type = sel->type->base;
575
+
576
+ for (a = f->args; NULL != a; a = a->next) {
577
+ if (NULL == (co = gql_object_create(err)) ||
578
+ AGOO_ERR_OK != gql_list_append(err, list, co)) {
579
+ return err->code;
580
+ }
581
+ child.ptr = a;
582
+ if (AGOO_ERR_OK != gql_eval_sels(err, doc, (gqlRef)&child, &cf, sel->sels, co, d2)) {
583
+ return err->code;
584
+ }
585
+ }
586
+ return AGOO_ERR_OK;
587
+ }
588
+
589
+ // type: __Type!
590
+ static int
591
+ field_type(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
592
+ gqlField f = (gqlField)obj->ptr;
593
+ const char *key = sel->name;
594
+ struct _gqlCobj child = { .clas = &type_class };
595
+ gqlValue co;
596
+
597
+ if (NULL != sel->alias) {
598
+ key = sel->alias;
599
+ }
600
+ if (NULL == f || NULL == f->type) {
601
+ co = gql_null_create(err);
602
+
603
+ return gql_object_set(err, result, key, co);
604
+ }
605
+ if (NULL == (co = gql_object_create(err)) ||
606
+ AGOO_ERR_OK != gql_object_set(err, result, key, co)) {
607
+ return err->code;
608
+ }
609
+ child.ptr = (void*)f->type;
610
+
611
+ return gql_eval_sels(err, doc, (gqlRef)&child, field, sel->sels, co, depth + 1);
612
+ }
613
+
614
+ // isDeprecated: Boolean!
615
+ static int
616
+ field_is_deprecated(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
617
+ const char *key = sel->name;
618
+
619
+ if (NULL != sel->alias) {
620
+ key = sel->alias;
621
+ }
622
+ return gql_object_set(err, result, key, gql_bool_create(err, is_deprecated(((gqlField)obj->ptr)->dir)));
623
+ }
624
+
625
+ // deprecationReason: String
626
+ static int
627
+ field_deprecation_reason(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
628
+ const char *reason = deprecation_reason(((gqlField)obj->ptr)->dir);
629
+ const char *key = sel->name;
630
+ gqlValue rv;
631
+
632
+ if (NULL != sel->alias) {
633
+ key = sel->alias;
634
+ }
635
+ if (NULL == reason) {
636
+ rv = gql_null_create(err);
637
+ } else {
638
+ rv = gql_string_create(err, reason, -1);
639
+ }
640
+ return gql_object_set(err, result, key, rv);
641
+ }
642
+
643
+ static struct _gqlCmethod field_methods[] = {
644
+ { .key = "name", .func = field_name },
645
+ { .key = "description", .func = field_description },
646
+ { .key = "args", .func = field_args },
647
+ { .key = "type", .func = field_type },
648
+ { .key = "isDeprecated", .func = field_is_deprecated },
649
+ { .key = "deprecationReason", .func = field_deprecation_reason },
650
+ { .key = NULL, .func = NULL },
651
+ };
652
+
653
+ static struct _gqlCclass field_class = {
654
+ .name = "__Field",
655
+ .methods = field_methods,
656
+ };
657
+
658
+ // EnumValue
659
+ // name: String!
660
+ static int
661
+ enum_value_name(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
662
+ const char *key = sel->name;
663
+
664
+ if (NULL != sel->alias) {
665
+ key = sel->alias;
666
+ }
667
+ return gql_object_set(err, result, key, gql_string_create(err, ((gqlEnumVal)obj->ptr)->value, -1));
668
+ }
669
+
670
+ // description: String
671
+ static int
672
+ enum_value_description(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
673
+ const char *key = sel->name;
674
+ const char *s = ((gqlEnumVal)obj->ptr)->desc;
675
+ gqlValue desc;
676
+
677
+ if (NULL != sel->alias) {
678
+ key = sel->alias;
679
+ }
680
+ if (NULL == s) {
681
+ desc = gql_null_create(err);
682
+ } else {
683
+ desc = gql_string_create(err, s, -1);
684
+ }
685
+ return gql_object_set(err, result, key, desc);
686
+ }
687
+
688
+ static int
689
+ enum_value_is_deprecated(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
690
+ const char *key = sel->name;
691
+
692
+ if (NULL != sel->alias) {
693
+ key = sel->alias;
694
+ }
695
+ return gql_object_set(err, result, key, gql_bool_create(err, is_deprecated(((gqlEnumVal)obj->ptr)->dir)));
696
+ }
697
+
698
+ static int
699
+ enum_value_deprecation_reason(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
700
+ const char *reason = deprecation_reason(((gqlEnumVal)obj->ptr)->dir);
701
+ const char *key = sel->name;
702
+ gqlValue rv;
703
+
704
+ if (NULL != sel->alias) {
705
+ key = sel->alias;
706
+ }
707
+ if (NULL == reason) {
708
+ rv = gql_null_create(err);
709
+ } else {
710
+ rv = gql_string_create(err, reason, -1);
711
+ }
712
+ return gql_object_set(err, result, key, rv);
713
+ }
714
+
715
+ static struct _gqlCmethod enum_value_methods[] = {
716
+ { .key = "name", .func = enum_value_name },
717
+ { .key = "description", .func = enum_value_description },
718
+ { .key = "isDeprecated", .func = enum_value_is_deprecated },
719
+ { .key = "deprecationReason", .func = enum_value_deprecation_reason },
720
+ { .key = NULL, .func = NULL },
721
+ };
722
+
723
+ static struct _gqlCclass enum_value_class = {
724
+ .name = "__EnumValue",
725
+ .methods = enum_value_methods,
726
+ };
727
+
728
+ // __Directive
729
+ // name: String!
730
+ static int
731
+ directive_name(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
732
+ const char *key = sel->name;
733
+
734
+ if (NULL != sel->alias) {
735
+ key = sel->alias;
736
+ }
737
+ return gql_object_set(err, result, key, gql_string_create(err, ((gqlDir)obj->ptr)->name, -1));
738
+ }
739
+
740
+ // description: String
741
+ static int
742
+ directive_description(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
743
+ const char *key = sel->name;
744
+ const char *s = ((gqlDir)obj->ptr)->desc;
745
+ gqlValue desc;
746
+
747
+ if (NULL != sel->alias) {
748
+ key = sel->alias;
749
+ }
750
+ if (NULL == s) {
751
+ desc = gql_null_create(err);
752
+ } else {
753
+ desc = gql_string_create(err, s, -1);
754
+ }
755
+ return gql_object_set(err, result, key, desc);
756
+ }
757
+
758
+ // locations: [__DirectiveLocation!]!
759
+ static int
760
+ directive_locations(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
761
+ gqlDir d = (gqlDir)obj->ptr;
762
+ const char *key = sel->name;
763
+ gqlStrLink locs = d->locs;
764
+ gqlValue list = gql_list_create(err, NULL);
765
+ gqlValue c;
766
+
767
+ if (NULL != sel->alias) {
768
+ key = sel->alias;
769
+ }
770
+ if (NULL == list ||
771
+ AGOO_ERR_OK != gql_object_set(err, result, key, list)) {
772
+ return err->code;
773
+ }
774
+ for (; NULL != locs; locs = locs->next) {
775
+ if (NULL == (c = gql_string_create(err, locs->str, -1)) ||
776
+ AGOO_ERR_OK != gql_list_append(err, list, c)) {
777
+ return err->code;
322
778
  }
323
779
  }
324
- for (f = type_type->fields; NULL != f; f = f->next) {
325
- if (0 == strcmp("fields", f->name)) {
326
- f->type = field_type;
327
- } else if (0 == strcmp("enumValues", f->name)) {
328
- f->type = enum_value_type;
329
- break;
780
+ return AGOO_ERR_OK;
781
+ }
782
+
783
+ static int
784
+ directive_args(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
785
+ gqlDir d = (gqlDir)obj->ptr;
786
+ const char *key = sel->name;
787
+ gqlArg a;
788
+ gqlValue list = gql_list_create(err, NULL);
789
+ gqlValue co;
790
+ struct _gqlField cf;
791
+ struct _gqlCobj child = { .clas = &input_value_class };
792
+ int d2 = depth + 1;
793
+
794
+ if (NULL != sel->alias) {
795
+ key = sel->alias;
796
+ }
797
+ if (NULL == list ||
798
+ AGOO_ERR_OK != gql_object_set(err, result, key, list)) {
799
+ return err->code;
800
+ }
801
+ memset(&cf, 0, sizeof(cf));
802
+ cf.type = sel->type->base;
803
+
804
+ for (a = d->args; NULL != a; a = a->next) {
805
+ if (NULL == (co = gql_object_create(err)) ||
806
+ AGOO_ERR_OK != gql_list_append(err, list, co)) {
807
+ return err->code;
808
+ }
809
+ child.ptr = a;
810
+ if (AGOO_ERR_OK != gql_eval_sels(err, doc, (gqlRef)&child, &cf, sel->sels, co, d2)) {
811
+ return err->code;
330
812
  }
331
813
  }
332
814
  return AGOO_ERR_OK;
333
815
  }
816
+
817
+ static struct _gqlCmethod directive_methods[] = {
818
+ { .key = "name", .func = directive_name },
819
+ { .key = "description", .func = directive_description },
820
+ { .key = "locations", .func = directive_locations },
821
+ { .key = "args", .func = directive_args },
822
+ { .key = NULL, .func = NULL },
823
+ };
824
+
825
+ static struct _gqlCclass directive_class = {
826
+ .name = "__Directive",
827
+ .methods = directive_methods,
828
+ };
829
+
830
+ // __Type
831
+ // kind: __TypeKind!
832
+ static int
833
+ type_kind(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
834
+ const char *kind = NULL;
835
+ const char *key = sel->name;
836
+
837
+ switch (((gqlType)obj->ptr)->kind) {
838
+ case GQL_OBJECT: kind = "OBJECT"; break;
839
+ case GQL_INPUT: kind = "INPUT_OBJECT"; break;
840
+ case GQL_UNION: kind = "UNION"; break;
841
+ case GQL_INTERFACE: kind = "INTERFACE"; break;
842
+ case GQL_ENUM: kind = "ENUM"; break;
843
+ case GQL_SCALAR: kind = "SCALAR"; break;
844
+ case GQL_LIST: kind = "LIST"; break;
845
+ default:
846
+ return agoo_err_set(err, AGOO_ERR_ARG, "__Type kind field not valid. %s:%d", __FILE__, __LINE__);
847
+ }
848
+ if (NULL != sel->alias) {
849
+ key = sel->alias;
850
+ }
851
+ return gql_object_set(err, result, key, gql_token_create(err, kind, -1, gql_type_get("__TypeKind")));
852
+ }
853
+
854
+ // name: String
855
+ static int
856
+ type_name(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
857
+ const char *key = sel->name;
858
+
859
+ if (NULL != sel->alias) {
860
+ key = sel->alias;
861
+ }
862
+ return gql_object_set(err, result, key, gql_string_create(err, ((gqlType)obj->ptr)->name, -1));
863
+ }
864
+
865
+ // description: String
866
+ static int
867
+ type_description(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
868
+ gqlType type = (gqlType)obj->ptr;
869
+ const char *key = sel->name;
870
+ gqlValue desc;
871
+
872
+ if (NULL != sel->alias) {
873
+ key = sel->alias;
874
+ }
875
+ if (NULL == type->desc) {
876
+ desc = gql_null_create(err);
877
+ } else {
878
+ desc = gql_string_create(err, type->desc, -1);
879
+ }
880
+ return gql_object_set(err, result, key, desc);
881
+ }
882
+
883
+ // OBJECT and INTERFACE only
884
+ // fields(includeDeprecated: Boolean = false): [__Field!]
885
+ static int
886
+ type_fields(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
887
+ gqlType type = (gqlType)obj->ptr;
888
+ const char *key = sel->name;
889
+ gqlField f;
890
+ gqlValue list = gql_list_create(err, NULL);
891
+ gqlValue co;
892
+ struct _gqlField cf;
893
+ struct _gqlCobj child = { .clas = &field_class };
894
+ int d2 = depth + 1;
895
+ gqlValue a = extract_arg(err, field, sel, "includeDeprecated");
896
+ bool inc_dep = false;
897
+
898
+ if (GQL_OBJECT != type->kind && GQL_INTERFACE != type->kind) {
899
+ if (NULL == (co = gql_null_create(err)) ||
900
+ AGOO_ERR_OK != gql_list_append(err, list, co)) {
901
+ return err->code;
902
+ }
903
+ return AGOO_ERR_OK;
904
+ }
905
+ if (NULL != a && GQL_SCALAR_BOOL == a->type->scalar_kind && a->b) {
906
+ inc_dep = true;
907
+ }
908
+ if (NULL != sel->alias) {
909
+ key = sel->alias;
910
+ }
911
+ if (NULL == list ||
912
+ AGOO_ERR_OK != gql_object_set(err, result, key, list)) {
913
+ return err->code;
914
+ }
915
+ memset(&cf, 0, sizeof(cf));
916
+ cf.type = sel->type->base;
917
+ for (f = type->fields; NULL != f; f = f->next) {
918
+ if (!inc_dep && is_deprecated(f->dir)) {
919
+ continue;
920
+ }
921
+ if (NULL == (co = gql_object_create(err)) ||
922
+ AGOO_ERR_OK != gql_list_append(err, list, co)) {
923
+ return err->code;
924
+ }
925
+ child.ptr = f;
926
+ if (AGOO_ERR_OK != gql_eval_sels(err, doc, (gqlRef)&child, &cf, sel->sels, co, d2)) {
927
+ return err->code;
928
+ }
929
+ }
930
+ return AGOO_ERR_OK;
931
+ }
932
+
933
+ // OBJECT only
934
+ // interfaces: [__Type!]
935
+ static int
936
+ type_interfaces(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
937
+ gqlType type = (gqlType)obj->ptr;
938
+ const char *key = sel->name;
939
+ gqlTypeLink tl;
940
+ gqlValue list = gql_list_create(err, NULL);
941
+ gqlValue co;
942
+ struct _gqlField cf;
943
+ struct _gqlCobj child = { .clas = &type_class };
944
+ int d2 = depth + 1;
945
+
946
+ if (GQL_OBJECT != type->kind) {
947
+ if (NULL == (co = gql_null_create(err)) ||
948
+ AGOO_ERR_OK != gql_list_append(err, list, co)) {
949
+ return err->code;
950
+ }
951
+ return AGOO_ERR_OK;
952
+ }
953
+ if (NULL != sel->alias) {
954
+ key = sel->alias;
955
+ }
956
+ if (NULL == list ||
957
+ AGOO_ERR_OK != gql_object_set(err, result, key, list)) {
958
+ return err->code;
959
+ }
960
+ memset(&cf, 0, sizeof(cf));
961
+ cf.type = sel->type->base;
962
+ for (tl = type->interfaces; NULL != tl; tl = tl->next) {
963
+ if (NULL == (co = gql_object_create(err)) ||
964
+ AGOO_ERR_OK != gql_list_append(err, list, co)) {
965
+ return err->code;
966
+ }
967
+ child.ptr = tl->type;
968
+ if (AGOO_ERR_OK != gql_eval_sels(err, doc, (gqlRef)&child, &cf, sel->sels, co, d2)) {
969
+ return err->code;
970
+ }
971
+ }
972
+ return AGOO_ERR_OK;
973
+ }
974
+
975
+ // INTERFACE and UNION only
976
+ // possibleTypes: [__Type!]
977
+ static bool
978
+ has_interface(gqlType type, gqlType interface) {
979
+ gqlTypeLink tl;
980
+
981
+ for (tl = type->interfaces; NULL != tl; tl = tl->next) {
982
+ if (tl->type == type) {
983
+ return true;
984
+ }
985
+ }
986
+ return false;
987
+ }
988
+
989
+ typedef struct _posCtx {
990
+ agooErr err;
991
+ gqlDoc doc;
992
+ gqlSel sel;
993
+ int depth;
994
+ gqlValue list;
995
+ gqlType interface;
996
+ gqlCobj child;
997
+ gqlField cf;
998
+ } *PosCtx;
999
+
1000
+ static void
1001
+ possible_cb(gqlType type, void *ctx) {
1002
+ PosCtx pc = (PosCtx)ctx;
1003
+
1004
+ if (AGOO_ERR_OK != pc->err->code) {
1005
+ return;
1006
+ }
1007
+ if (GQL_LIST != type->kind && has_interface(type, pc->interface)) {
1008
+ gqlValue co;
1009
+
1010
+ if (NULL == (co = gql_object_create(pc->err)) ||
1011
+ AGOO_ERR_OK != gql_list_append(pc->err, pc->list, co)) {
1012
+ return;
1013
+ }
1014
+ pc->child->ptr = type;
1015
+ gql_eval_sels(pc->err, pc->doc, (gqlRef)pc->child, pc->cf, pc->sel->sels, co, pc->depth);
1016
+ }
1017
+ }
1018
+
1019
+ static int
1020
+ type_possible_types(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
1021
+ gqlType type = (gqlType)obj->ptr;
1022
+ const char *key = sel->name;
1023
+ gqlTypeLink tl;
1024
+ gqlValue list = gql_list_create(err, NULL);
1025
+ gqlValue co;
1026
+ struct _gqlField cf;
1027
+ struct _gqlCobj child = { .clas = &type_class };
1028
+ int d2 = depth + 1;
1029
+
1030
+ if (NULL != sel->alias) {
1031
+ key = sel->alias;
1032
+ }
1033
+ if (NULL == list ||
1034
+ AGOO_ERR_OK != gql_object_set(err, result, key, list)) {
1035
+ return err->code;
1036
+ }
1037
+ memset(&cf, 0, sizeof(cf));
1038
+ cf.type = sel->type->base;
1039
+
1040
+ switch (type->kind) {
1041
+ case GQL_INTERFACE: {
1042
+ struct _posCtx pc = {
1043
+ .err = err,
1044
+ .doc = doc,
1045
+ .sel = sel,
1046
+ .depth = depth + 1,
1047
+ .list = list,
1048
+ .interface = type,
1049
+ .child = &child,
1050
+ .cf = &cf,
1051
+ };
1052
+
1053
+ gql_type_iterate(possible_cb, &pc);
1054
+ break;
1055
+ }
1056
+ case GQL_UNION:
1057
+ for (tl = type->types; NULL != tl; tl = tl->next) {
1058
+ if (NULL == (co = gql_object_create(err)) ||
1059
+ AGOO_ERR_OK != gql_list_append(err, list, co)) {
1060
+ return err->code;
1061
+ }
1062
+ child.ptr = tl->type;
1063
+ if (AGOO_ERR_OK != gql_eval_sels(err, doc, (gqlRef)&child, &cf, sel->sels, co, d2)) {
1064
+ return err->code;
1065
+ }
1066
+ }
1067
+ break;
1068
+ default:
1069
+ if (NULL == (co = gql_null_create(err)) ||
1070
+ AGOO_ERR_OK != gql_list_append(err, list, co)) {
1071
+ return err->code;
1072
+ }
1073
+ }
1074
+ return AGOO_ERR_OK;
1075
+ }
1076
+
1077
+ // ENUM only
1078
+ // enumValues(includeDeprecated: Boolean = false): [__EnumValue!]
1079
+ static int
1080
+ type_enum_values(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
1081
+ gqlType type = (gqlType)obj->ptr;
1082
+ const char *key = sel->name;
1083
+ gqlEnumVal c;
1084
+ gqlValue list = gql_list_create(err, NULL);
1085
+ gqlValue co;
1086
+ struct _gqlField cf;
1087
+ struct _gqlCobj child = { .clas = &enum_value_class };
1088
+ int d2 = depth + 1;
1089
+ gqlValue a = extract_arg(err, field, sel, "includeDeprecated");
1090
+ bool inc_dep = false;
1091
+
1092
+ if (GQL_ENUM != type->kind) {
1093
+ if (NULL == (co = gql_null_create(err)) ||
1094
+ AGOO_ERR_OK != gql_list_append(err, list, co)) {
1095
+ return err->code;
1096
+ }
1097
+ return AGOO_ERR_OK;
1098
+ }
1099
+ if (NULL != a && GQL_SCALAR_BOOL == a->type->scalar_kind && a->b) {
1100
+ inc_dep = true;
1101
+ }
1102
+ if (NULL != sel->alias) {
1103
+ key = sel->alias;
1104
+ }
1105
+ if (NULL == list ||
1106
+ AGOO_ERR_OK != gql_object_set(err, result, key, list)) {
1107
+ return err->code;
1108
+ }
1109
+ memset(&cf, 0, sizeof(cf));
1110
+ cf.type = sel->type->base;
1111
+ for (c = type->choices; NULL != c; c = c->next) {
1112
+ if (!inc_dep && is_deprecated(c->dir)) {
1113
+ continue;
1114
+ }
1115
+ if (NULL == (co = gql_object_create(err)) ||
1116
+ AGOO_ERR_OK != gql_list_append(err, list, co)) {
1117
+ return err->code;
1118
+ }
1119
+ child.ptr = c;
1120
+ if (AGOO_ERR_OK != gql_eval_sels(err, doc, (gqlRef)&child, &cf, sel->sels, co, d2)) {
1121
+ return err->code;
1122
+ }
1123
+ }
1124
+ return AGOO_ERR_OK;
1125
+ }
1126
+
1127
+ // INPUT_OBJECT only
1128
+ // inputFields: [__InputValue!]
1129
+ static int
1130
+ type_input_fields(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
1131
+ gqlType type = (gqlType)obj->ptr;
1132
+ const char *key = sel->name;
1133
+ gqlArg a;
1134
+ gqlValue list = gql_list_create(err, NULL);
1135
+ gqlValue co;
1136
+ struct _gqlField cf;
1137
+ struct _gqlCobj child = { .clas = &input_value_class };
1138
+ int d2 = depth + 1;
1139
+
1140
+ if (GQL_INPUT != type->kind) {
1141
+ if (NULL == (co = gql_null_create(err)) ||
1142
+ AGOO_ERR_OK != gql_list_append(err, list, co)) {
1143
+ return err->code;
1144
+ }
1145
+ return AGOO_ERR_OK;
1146
+ }
1147
+ if (NULL != sel->alias) {
1148
+ key = sel->alias;
1149
+ }
1150
+ if (NULL == list ||
1151
+ AGOO_ERR_OK != gql_object_set(err, result, key, list)) {
1152
+ return err->code;
1153
+ }
1154
+ memset(&cf, 0, sizeof(cf));
1155
+ cf.type = sel->type->base;
1156
+
1157
+ for (a = type->args; NULL != a; a = a->next) {
1158
+ if (NULL == (co = gql_object_create(err)) ||
1159
+ AGOO_ERR_OK != gql_list_append(err, list, co)) {
1160
+ return err->code;
1161
+ }
1162
+ child.ptr = a;
1163
+ if (AGOO_ERR_OK != gql_eval_sels(err, doc, (gqlRef)&child, &cf, sel->sels, co, d2)) {
1164
+ return err->code;
1165
+ }
1166
+ }
1167
+ return AGOO_ERR_OK;
1168
+ }
1169
+
1170
+ // NON_NULL and LIST only
1171
+ // ofType: __Type
1172
+ static int
1173
+ type_of_type(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
1174
+ gqlType type = (gqlType)obj->ptr;
1175
+ const char *key = sel->name;
1176
+ struct _gqlCobj child = { .clas = &type_class };
1177
+ gqlValue co;
1178
+
1179
+ if (NULL != sel->alias) {
1180
+ key = sel->alias;
1181
+ }
1182
+ if (NULL == type || NULL == type->base || (GQL_LIST != type->kind && GQL_NON_NULL != type->kind)) {
1183
+ co = gql_null_create(err);
1184
+
1185
+ return gql_object_set(err, result, key, co);
1186
+ }
1187
+ if (NULL == (co = gql_object_create(err)) ||
1188
+ AGOO_ERR_OK != gql_object_set(err, result, key, co)) {
1189
+ return err->code;
1190
+ }
1191
+ child.ptr = (void*)type->base;
1192
+
1193
+ return gql_eval_sels(err, doc, (gqlRef)&child, field, sel->sels, co, depth + 1);
1194
+ }
1195
+
1196
+ static struct _gqlCmethod type_methods[] = {
1197
+ { .key = "kind", .func = type_kind },
1198
+ { .key = "name", .func = type_name },
1199
+ { .key = "description", .func = type_description },
1200
+ { .key = "fields", .func = type_fields },
1201
+ { .key = "interfaces", .func = type_interfaces },
1202
+ { .key = "possibleTypes", .func = type_possible_types },
1203
+ { .key = "enumValues", .func = type_enum_values },
1204
+ { .key = "inputFields", .func = type_input_fields },
1205
+ { .key = "ofType", .func = type_of_type },
1206
+ { .key = NULL, .func = NULL },
1207
+ };
1208
+
1209
+ // __Type
1210
+ static struct _gqlCclass type_class = {
1211
+ .name = "__Type",
1212
+ .methods = type_methods,
1213
+ };
1214
+
1215
+ // __Schema
1216
+ typedef struct _schemaCbCtx {
1217
+ agooErr err;
1218
+ gqlDoc doc;
1219
+ gqlSel sel;
1220
+ int depth;
1221
+ gqlValue list;
1222
+ } *SchemaCbCtx;
1223
+
1224
+ static void
1225
+ schema_types_cb(gqlType type, void *ctx) {
1226
+ SchemaCbCtx scc = (SchemaCbCtx)ctx;
1227
+ gqlValue co;
1228
+ struct _gqlCobj child = { .clas = &type_class, .ptr = (void*)type };
1229
+ struct _gqlField cf;
1230
+
1231
+ if (AGOO_ERR_OK != scc->err->code || GQL_LIST == type->kind) {
1232
+ return;
1233
+ }
1234
+ memset(&cf, 0, sizeof(cf));
1235
+ cf.type = scc->sel->type->base;
1236
+
1237
+ if (NULL == (co = gql_object_create(scc->err)) ||
1238
+ AGOO_ERR_OK != gql_list_append(scc->err, scc->list, co)) {
1239
+ return;
1240
+ }
1241
+ gql_eval_sels(scc->err, scc->doc, (gqlRef)&child, &cf, scc->sel->sels, co, scc->depth);
1242
+ }
1243
+
1244
+ // types: [__Type!]!
1245
+ static int
1246
+ schema_types(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
1247
+ const char *key = sel->name;
1248
+ gqlValue list = gql_list_create(err, NULL);
1249
+ struct _schemaCbCtx scc = {
1250
+ .err = err,
1251
+ .doc = doc,
1252
+ .sel = sel,
1253
+ .depth = depth + 1,
1254
+ .list = list,
1255
+ };
1256
+
1257
+ if (NULL != sel->alias) {
1258
+ key = sel->alias;
1259
+ }
1260
+ if (NULL == list ||
1261
+ AGOO_ERR_OK != gql_object_set(err, result, key, list)) {
1262
+ return err->code;
1263
+ }
1264
+ gql_type_iterate(schema_types_cb, &scc);
1265
+
1266
+ return err->code;
1267
+ }
1268
+
1269
+ static int
1270
+ schema_op_type(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth, const char *op) {
1271
+ const char *key = sel->name;
1272
+ struct _gqlCobj child = { .clas = &type_class };
1273
+ gqlValue co;
1274
+ gqlType type;
1275
+
1276
+ if (NULL != sel->alias) {
1277
+ key = sel->alias;
1278
+ }
1279
+ if (NULL == (type = gql_type_func(gql_root_op(op)))) {
1280
+ if (NULL == (co = gql_null_create(err)) ||
1281
+ AGOO_ERR_OK != gql_object_set(err, result, key, co)) {
1282
+ return err->code;
1283
+ }
1284
+ return AGOO_ERR_OK;
1285
+ }
1286
+ if (NULL == (co = gql_object_create(err)) ||
1287
+ AGOO_ERR_OK != gql_object_set(err, result, key, co)) {
1288
+ return err->code;
1289
+ }
1290
+ child.ptr = (void*)type;
1291
+
1292
+ return gql_eval_sels(err, doc, (gqlRef)&child, field, sel->sels, co, depth + 1);
1293
+ }
1294
+
1295
+ // queryType: __Type!
1296
+ static int
1297
+ schema_query_type(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
1298
+ return schema_op_type(err, doc, obj, field, sel, result, depth, "query");
1299
+ }
1300
+
1301
+ // mutationType: __Type
1302
+ static int
1303
+ schema_mutation_type(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
1304
+ return schema_op_type(err, doc, obj, field, sel, result, depth, "mutation");
1305
+ }
1306
+
1307
+ // subscriptionType: __Type
1308
+ static int
1309
+ schema_subscription_type(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
1310
+ return schema_op_type(err, doc, obj, field, sel, result, depth, "subscription");
1311
+ }
1312
+
1313
+ // directives: [__Directive!]!
1314
+ static int
1315
+ schema_directives(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
1316
+ const char *key = sel->name;
1317
+ gqlValue list = gql_list_create(err, NULL);
1318
+ gqlValue co;
1319
+ struct _gqlField cf;
1320
+ struct _gqlCobj child = { .clas = &directive_class };
1321
+ int d2 = depth + 1;
1322
+ gqlDir d = gql_directives;
1323
+
1324
+ if (NULL != sel->alias) {
1325
+ key = sel->alias;
1326
+ }
1327
+ if (NULL == list ||
1328
+ AGOO_ERR_OK != gql_object_set(err, result, key, list)) {
1329
+ return err->code;
1330
+ }
1331
+ memset(&cf, 0, sizeof(cf));
1332
+ cf.type = sel->type->base;
1333
+
1334
+ for (d = gql_directives; NULL != d; d = d->next) {
1335
+ if (NULL == (co = gql_object_create(err)) ||
1336
+ AGOO_ERR_OK != gql_list_append(err, list, co)) {
1337
+ return err->code;
1338
+ }
1339
+ child.ptr = d;
1340
+ if (AGOO_ERR_OK != gql_eval_sels(err, doc, (gqlRef)&child, &cf, sel->sels, co, d2)) {
1341
+ return err->code;
1342
+ }
1343
+ }
1344
+ return AGOO_ERR_OK;
1345
+ }
1346
+
1347
+ static struct _gqlCmethod schema_methods[] = {
1348
+ { .key = "types", .func = schema_types },
1349
+ { .key = "queryType", .func = schema_query_type },
1350
+ { .key = "mutationType", .func = schema_mutation_type },
1351
+ { .key = "subscriptionType", .func = schema_subscription_type },
1352
+ { .key = "directives", .func = schema_directives },
1353
+ { .key = NULL, .func = NULL },
1354
+ };
1355
+
1356
+ static struct _gqlCclass schema_class = {
1357
+ .name = "__Schema",
1358
+ .methods = schema_methods,
1359
+ };
1360
+
1361
+ static int
1362
+ root_schema(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
1363
+ struct _gqlCobj child = { .clas = &schema_class, .ptr = NULL };
1364
+ gqlValue co;
1365
+ const char *key = sel->name;
1366
+
1367
+ if (NULL != sel->alias) {
1368
+ key = sel->alias;
1369
+ }
1370
+ if (NULL == (co = gql_object_create(err)) ||
1371
+ AGOO_ERR_OK != gql_object_set(err, result, key, co)) {
1372
+ return err->code;
1373
+ }
1374
+ return gql_eval_sels(err, doc, (gqlRef)&child, field, sel->sels, co, depth + 1);
1375
+ }
1376
+
1377
+ static int
1378
+ root_type(agooErr err, gqlDoc doc, gqlCobj obj, gqlField field, gqlSel sel, gqlValue result, int depth) {
1379
+ gqlValue na = extract_arg(err, field, sel, "name");
1380
+ const char *name = NULL;
1381
+ const char *key = sel->name;
1382
+ int d2 = depth + 1;
1383
+ gqlType type;
1384
+ gqlValue co;
1385
+ struct _gqlCobj child = { .clas = &type_class };
1386
+
1387
+ if (NULL != na) {
1388
+ name = gql_string_get(na);
1389
+ }
1390
+ if (NULL == name) {
1391
+ return agoo_err_set(err, AGOO_ERR_ARG, "%s field requires a name argument. %s:%d", sel->name, __FILE__, __LINE__);
1392
+ }
1393
+ if (NULL == (type = gql_type_get(name))) {
1394
+ return agoo_err_set(err, AGOO_ERR_ARG, "%s is not a defined type. %s:%d", name, __FILE__, __LINE__);
1395
+ }
1396
+ if (NULL != sel->alias) {
1397
+ key = sel->alias;
1398
+ }
1399
+ if (NULL == (co = gql_object_create(err)) ||
1400
+ AGOO_ERR_OK != gql_object_set(err, result, key, co)) {
1401
+ return err->code;
1402
+ }
1403
+ child.ptr = type;
1404
+ if (AGOO_ERR_OK != gql_eval_sels(err, doc, (gqlRef)&child, field, sel->sels, co, d2)) {
1405
+ return err->code;
1406
+ }
1407
+ return AGOO_ERR_OK;
1408
+ }
1409
+
1410
+ static struct _gqlCmethod root_methods[] = {
1411
+ { .key = "__type", .func = root_type },
1412
+ { .key = "__schema", .func = root_schema },
1413
+ { .key = NULL, .func = NULL },
1414
+ };
1415
+
1416
+ static struct _gqlCclass root_class = {
1417
+ .name = "__Query",
1418
+ .methods = root_methods,
1419
+ };
1420
+
1421
+ static gqlType
1422
+ ref_type(gqlRef ref) {
1423
+ gqlCobj obj = (gqlCobj)ref;
1424
+
1425
+ if (NULL != obj && NULL != obj->clas) {
1426
+ return gql_type_get(obj->clas->name);
1427
+ }
1428
+ return NULL;
1429
+ }
1430
+
1431
+ static int
1432
+ resolve(agooErr err, gqlDoc doc, gqlRef target, gqlField field, gqlSel sel, gqlValue result, int depth) {
1433
+ gqlCobj obj = (gqlCobj)target;
1434
+ gqlCmethod method;
1435
+
1436
+ for (method = obj->clas->methods; NULL != method->key; method++) {
1437
+ if (0 == strcmp(method->key, sel->name)) {
1438
+ return method->func(err, doc, obj, field, sel, result, depth);
1439
+ }
1440
+ }
1441
+ return agoo_err_set(err, AGOO_ERR_EVAL, "%s is not a field on %s.", sel->name, obj->clas->name);
1442
+ }
1443
+
1444
+ int
1445
+ gql_intro_eval(agooErr err, gqlDoc doc, gqlSel sel, gqlValue result, int depth) {
1446
+ struct _gqlField field;
1447
+ struct _gqlCobj obj;
1448
+
1449
+ if (0 == strcmp("__type", sel->name)) {
1450
+ if (1 < depth) {
1451
+ return agoo_err_set(err, AGOO_ERR_EVAL, "__type can only be called from a query root.");
1452
+ }
1453
+ obj.clas = &root_class;
1454
+ obj.ptr = NULL;
1455
+ } else if (0 == strcmp("__schema", sel->name)) {
1456
+ if (1 < depth) {
1457
+ return agoo_err_set(err, AGOO_ERR_EVAL, "__scheme can only be called from a query root.");
1458
+ }
1459
+ obj.clas = &root_class;
1460
+ obj.ptr = NULL;
1461
+ } else {
1462
+ return agoo_err_set(err, AGOO_ERR_EVAL, "%s can only be called from the query root.", sel->name);
1463
+ }
1464
+ memset(&field, 0, sizeof(field));
1465
+ field.name = sel->name;
1466
+ field.type = sel->type;
1467
+
1468
+ doc->funcs.resolve = resolve;
1469
+ doc->funcs.type = ref_type;
1470
+
1471
+ return resolve(err, doc, &obj, &field, sel, result, depth);
1472
+ }
1473
+