agoo 2.11.7 → 2.13.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +48 -0
- data/bin/agoo_stubs +166 -0
- data/ext/agoo/bind.c +7 -5
- data/ext/agoo/con.c +1 -1
- data/ext/agoo/gqleval.c +87 -23
- data/ext/agoo/gqleval.h +6 -0
- data/ext/agoo/gqlintro.c +175 -103
- data/ext/agoo/gqljson.c +3 -0
- data/ext/agoo/gqlvalue.c +5 -5
- data/ext/agoo/graphql.c +35 -24
- data/ext/agoo/graphql.h +11 -15
- data/ext/agoo/req.c +9 -10
- data/ext/agoo/rgraphql.c +248 -12
- data/ext/agoo/rserver.c +52 -5
- data/ext/agoo/rserver.h +8 -0
- data/ext/agoo/sdl.c +23 -26
- data/ext/agoo/sdl.h +1 -1
- data/lib/agoo.rb +1 -0
- data/lib/agoo/graphql.rb +9 -0
- data/lib/agoo/graphql/arg.rb +13 -0
- data/lib/agoo/graphql/field.rb +14 -0
- data/lib/agoo/graphql/type.rb +12 -0
- data/lib/agoo/version.rb +1 -1
- data/test/graphql_test.rb +22 -18
- metadata +8 -2
data/ext/agoo/gqljson.c
CHANGED
@@ -424,6 +424,7 @@ parse_value(agooErr err, agooDoc doc) {
|
|
424
424
|
if (4 <= doc->end - doc->cur &&
|
425
425
|
'r' == doc->cur[1] && 'u' == doc->cur[2] && 'e' == doc->cur[3]) {
|
426
426
|
value = gql_bool_create(err, true);
|
427
|
+
doc->cur += 4;
|
427
428
|
} else {
|
428
429
|
agoo_doc_err(doc, err, "invalid token");
|
429
430
|
}
|
@@ -432,6 +433,7 @@ parse_value(agooErr err, agooDoc doc) {
|
|
432
433
|
if (5 <= doc->end - doc->cur &&
|
433
434
|
'a' == doc->cur[1] && 'l' == doc->cur[2] && 's' == doc->cur[3] && 'e' == doc->cur[4]) {
|
434
435
|
value = gql_bool_create(err, false);
|
436
|
+
doc->cur += 5;
|
435
437
|
} else {
|
436
438
|
agoo_doc_err(doc, err, "invalid token");
|
437
439
|
}
|
@@ -440,6 +442,7 @@ parse_value(agooErr err, agooDoc doc) {
|
|
440
442
|
if (4 <= doc->end - doc->cur &&
|
441
443
|
'u' == doc->cur[1] && 'l' == doc->cur[2] && 'l' == doc->cur[3]) {
|
442
444
|
value = gql_null_create(err);
|
445
|
+
doc->cur += 4;
|
443
446
|
} else {
|
444
447
|
agoo_doc_err(doc, err, "invalid token");
|
445
448
|
}
|
data/ext/agoo/gqlvalue.c
CHANGED
@@ -590,8 +590,7 @@ list_destroy(gqlValue value) {
|
|
590
590
|
|
591
591
|
while (NULL != (link = value->members)) {
|
592
592
|
value->members = link->next;
|
593
|
-
|
594
|
-
AGOO_FREE(link);
|
593
|
+
gql_link_destroy(link);
|
595
594
|
}
|
596
595
|
}
|
597
596
|
|
@@ -679,9 +678,7 @@ object_destroy(gqlValue value) {
|
|
679
678
|
|
680
679
|
while (NULL != (link = value->members)) {
|
681
680
|
value->members = link->next;
|
682
|
-
|
683
|
-
AGOO_FREE(link->key);
|
684
|
-
AGOO_FREE(link);
|
681
|
+
gql_link_destroy(link);
|
685
682
|
}
|
686
683
|
}
|
687
684
|
|
@@ -1572,6 +1569,9 @@ int
|
|
1572
1569
|
gql_value_convert(agooErr err, gqlValue value, gqlType type) {
|
1573
1570
|
int code = AGOO_ERR_OK;
|
1574
1571
|
|
1572
|
+
if (GQL_NON_NULL == type->kind) {
|
1573
|
+
type = type->base;
|
1574
|
+
}
|
1575
1575
|
if (type != value->type) {
|
1576
1576
|
switch (type->scalar_kind) {
|
1577
1577
|
case GQL_SCALAR_BOOL:
|
data/ext/agoo/graphql.c
CHANGED
@@ -517,8 +517,7 @@ gql_type_field(agooErr err,
|
|
517
517
|
gqlType return_type,
|
518
518
|
gqlValue default_value,
|
519
519
|
const char *desc,
|
520
|
-
size_t dlen
|
521
|
-
bool required) {
|
520
|
+
size_t dlen) {
|
522
521
|
gqlField f = (gqlField)AGOO_MALLOC(sizeof(struct _gqlField));
|
523
522
|
|
524
523
|
if (NULL == f) {
|
@@ -538,7 +537,6 @@ gql_type_field(agooErr err,
|
|
538
537
|
f->args = NULL;
|
539
538
|
f->dir = NULL;
|
540
539
|
f->default_value = default_value;
|
541
|
-
f->required = required;
|
542
540
|
if (NULL == type->fields) {
|
543
541
|
type->fields = f;
|
544
542
|
} else {
|
@@ -559,8 +557,7 @@ gql_field_arg(agooErr err,
|
|
559
557
|
gqlType type,
|
560
558
|
const char *desc,
|
561
559
|
size_t dlen,
|
562
|
-
struct _gqlValue *def_value
|
563
|
-
bool required) {
|
560
|
+
struct _gqlValue *def_value) {
|
564
561
|
gqlArg a = (gqlArg)AGOO_MALLOC(sizeof(struct _gqlArg));
|
565
562
|
|
566
563
|
if (NULL == a) {
|
@@ -579,7 +576,6 @@ gql_field_arg(agooErr err,
|
|
579
576
|
}
|
580
577
|
a->default_value = def_value;
|
581
578
|
a->dir = NULL;
|
582
|
-
a->required = required;
|
583
579
|
if (NULL == field->args) {
|
584
580
|
field->args = a;
|
585
581
|
} else {
|
@@ -600,8 +596,7 @@ gql_input_arg(agooErr err,
|
|
600
596
|
gqlType type,
|
601
597
|
const char *desc,
|
602
598
|
size_t dlen,
|
603
|
-
struct _gqlValue *def_value
|
604
|
-
bool required) {
|
599
|
+
struct _gqlValue *def_value) {
|
605
600
|
gqlArg a = (gqlArg)AGOO_MALLOC(sizeof(struct _gqlArg));
|
606
601
|
|
607
602
|
if (NULL == a) {
|
@@ -620,7 +615,6 @@ gql_input_arg(agooErr err,
|
|
620
615
|
}
|
621
616
|
a->default_value = def_value;
|
622
617
|
a->dir = NULL;
|
623
|
-
a->required = required;
|
624
618
|
if (NULL == input->args) {
|
625
619
|
input->args = a;
|
626
620
|
} else {
|
@@ -801,8 +795,7 @@ gql_dir_arg(agooErr err,
|
|
801
795
|
gqlType type,
|
802
796
|
const char *desc,
|
803
797
|
size_t dlen,
|
804
|
-
struct _gqlValue *def_value
|
805
|
-
bool required) {
|
798
|
+
struct _gqlValue *def_value) {
|
806
799
|
|
807
800
|
gqlArg a = (gqlArg)AGOO_MALLOC(sizeof(struct _gqlArg));
|
808
801
|
|
@@ -822,7 +815,6 @@ gql_dir_arg(agooErr err,
|
|
822
815
|
}
|
823
816
|
a->default_value = def_value;
|
824
817
|
a->dir = NULL;
|
825
|
-
a->required = required;
|
826
818
|
if (NULL == dir->args) {
|
827
819
|
dir->args = a;
|
828
820
|
} else {
|
@@ -863,11 +855,11 @@ gql_directive_on(agooErr err, gqlDir d, const char *on, int len) {
|
|
863
855
|
}
|
864
856
|
|
865
857
|
gqlType
|
866
|
-
gql_assure_list(agooErr err, gqlType base
|
858
|
+
gql_assure_list(agooErr err, gqlType base) {
|
867
859
|
char name[256];
|
868
860
|
gqlType type;
|
869
861
|
|
870
|
-
if ((int)sizeof(name) <= snprintf(name, sizeof(name), "[%s
|
862
|
+
if ((int)sizeof(name) <= snprintf(name, sizeof(name), "[%s]", base->name)) {
|
871
863
|
agoo_err_set(err, AGOO_ERR_ARG, "Name too long");
|
872
864
|
return NULL;
|
873
865
|
}
|
@@ -876,7 +868,24 @@ gql_assure_list(agooErr err, gqlType base, bool not_empty) {
|
|
876
868
|
return NULL;
|
877
869
|
}
|
878
870
|
type->base = base;
|
879
|
-
|
871
|
+
}
|
872
|
+
return type;
|
873
|
+
}
|
874
|
+
|
875
|
+
gqlType
|
876
|
+
gql_assure_nonnull(agooErr err, gqlType base) {
|
877
|
+
char name[256];
|
878
|
+
gqlType type;
|
879
|
+
|
880
|
+
if ((int)sizeof(name) <= snprintf(name, sizeof(name), "%s!", base->name)) {
|
881
|
+
agoo_err_set(err, AGOO_ERR_ARG, "Name too long");
|
882
|
+
return NULL;
|
883
|
+
}
|
884
|
+
if (NULL == (type = gql_type_get(name))) {
|
885
|
+
if (NULL == (type = type_create(err, GQL_NON_NULL, name, NULL, 0))) {
|
886
|
+
return NULL;
|
887
|
+
}
|
888
|
+
type->base = base;
|
880
889
|
}
|
881
890
|
return type;
|
882
891
|
}
|
@@ -988,9 +997,6 @@ arg_sdl(agooText text, gqlArg a, bool with_desc, bool same_line, bool last) {
|
|
988
997
|
if (NULL != a->type) { // should always be true
|
989
998
|
text = agoo_text_append(text, a->type->name, -1);
|
990
999
|
}
|
991
|
-
if (a->required) {
|
992
|
-
text = agoo_text_append(text, "!", 1);
|
993
|
-
}
|
994
1000
|
if (NULL != a->default_value) {
|
995
1001
|
text = agoo_text_append(text, " = ", 3);
|
996
1002
|
text = gql_value_sdl(text, a->default_value, 0, 0);
|
@@ -1024,9 +1030,6 @@ field_sdl(agooText text, gqlField f, bool with_desc) {
|
|
1024
1030
|
}
|
1025
1031
|
text = agoo_text_append(text, ": ", 2);
|
1026
1032
|
text = agoo_text_append(text, f->type->name, -1);
|
1027
|
-
if (f->required) {
|
1028
|
-
text = agoo_text_append(text, "!", 1);
|
1029
|
-
}
|
1030
1033
|
if (NULL != f->default_value) {
|
1031
1034
|
text = agoo_text_append(text, " = ", 3);
|
1032
1035
|
text = gql_value_sdl(text, f->default_value, 0, 0);
|
@@ -1204,7 +1207,7 @@ gql_schema_sdl(agooText text, bool with_desc, bool all) {
|
|
1204
1207
|
for (bucket = buckets, i = 0; i < BUCKET_SIZE; bucket++, i++) {
|
1205
1208
|
for (s = *bucket; NULL != s; s = s->next) {
|
1206
1209
|
type = s->type;
|
1207
|
-
if (GQL_LIST == type->kind) {
|
1210
|
+
if (GQL_LIST == type->kind || GQL_NON_NULL == type->kind) {
|
1208
1211
|
continue;
|
1209
1212
|
}
|
1210
1213
|
if (!all && type->core) {
|
@@ -1216,11 +1219,12 @@ gql_schema_sdl(agooText text, bool with_desc, bool all) {
|
|
1216
1219
|
if (0 < cnt) {
|
1217
1220
|
gqlType types[cnt];
|
1218
1221
|
gqlType *tp = types;
|
1222
|
+
long len;
|
1219
1223
|
|
1220
1224
|
for (bucket = buckets, i = 0; i < BUCKET_SIZE; bucket++, i++) {
|
1221
1225
|
for (s = *bucket; NULL != s; s = s->next) {
|
1222
1226
|
type = s->type;
|
1223
|
-
if (GQL_LIST == type->kind) {
|
1227
|
+
if (GQL_LIST == type->kind || GQL_NON_NULL == type->kind) {
|
1224
1228
|
continue;
|
1225
1229
|
}
|
1226
1230
|
if (!all && type->core) {
|
@@ -1231,8 +1235,9 @@ gql_schema_sdl(agooText text, bool with_desc, bool all) {
|
|
1231
1235
|
}
|
1232
1236
|
qsort(types, cnt, sizeof(gqlType), type_cmp);
|
1233
1237
|
for (i = 0, tp = types; i < cnt; i++, tp++) {
|
1238
|
+
len = text->len;
|
1234
1239
|
text = gql_type_sdl(text, *tp, with_desc);
|
1235
|
-
if (i < cnt - 1) {
|
1240
|
+
if (i < cnt - 1 && len < text->len) {
|
1236
1241
|
text = agoo_text_append(text, "\n", 1);
|
1237
1242
|
}
|
1238
1243
|
}
|
@@ -1355,6 +1360,9 @@ gql_doc_create(agooErr err) {
|
|
1355
1360
|
doc->ops = NULL;
|
1356
1361
|
doc->vars = NULL;
|
1357
1362
|
doc->frags = NULL;
|
1363
|
+
doc->req = NULL;
|
1364
|
+
doc->ctx = NULL;
|
1365
|
+
doc->ctx_free = NULL;
|
1358
1366
|
}
|
1359
1367
|
return doc;
|
1360
1368
|
}
|
@@ -1474,6 +1482,9 @@ gql_doc_destroy(gqlDoc doc) {
|
|
1474
1482
|
doc->frags = frag->next;
|
1475
1483
|
gql_frag_destroy(frag);
|
1476
1484
|
}
|
1485
|
+
if (NULL != doc->ctx_free) {
|
1486
|
+
doc->ctx_free(doc->ctx);
|
1487
|
+
}
|
1477
1488
|
AGOO_FREE(doc);
|
1478
1489
|
}
|
1479
1490
|
|
data/ext/agoo/graphql.h
CHANGED
@@ -88,7 +88,6 @@ typedef struct _gqlArg {
|
|
88
88
|
struct _gqlType *type;
|
89
89
|
struct _gqlValue *default_value;
|
90
90
|
struct _gqlDirUse *dir;
|
91
|
-
bool required;
|
92
91
|
} *gqlArg;
|
93
92
|
|
94
93
|
typedef struct _gqlField {
|
@@ -99,7 +98,6 @@ typedef struct _gqlField {
|
|
99
98
|
gqlArg args;
|
100
99
|
struct _gqlDirUse *dir;
|
101
100
|
struct _gqlValue *default_value;
|
102
|
-
bool required;
|
103
101
|
} *gqlField;
|
104
102
|
|
105
103
|
typedef struct _gqlDir {
|
@@ -133,15 +131,12 @@ typedef struct _gqlType {
|
|
133
131
|
gqlTypeLink types; // Union
|
134
132
|
gqlEnumVal choices; // Enums
|
135
133
|
gqlArg args; // InputObject
|
134
|
+
struct _gqlType *base; // List and NonNull types
|
136
135
|
struct { // scalar
|
137
136
|
agooText (*to_sdl)(agooText text, struct _gqlValue *value, int indent, int depth);
|
138
137
|
agooText (*to_json)(agooText text, struct _gqlValue *value, int indent, int depth);
|
139
138
|
void (*destroy)(struct _gqlValue *value);
|
140
139
|
};
|
141
|
-
struct { // List types
|
142
|
-
struct _gqlType *base;
|
143
|
-
bool not_empty;
|
144
|
-
};
|
145
140
|
};
|
146
141
|
} *gqlType;
|
147
142
|
|
@@ -202,6 +197,9 @@ typedef struct _gqlDoc {
|
|
202
197
|
gqlFrag frags;
|
203
198
|
gqlOp op; // the op to execute
|
204
199
|
struct _gqlFuncs funcs;
|
200
|
+
struct _agooReq *req;
|
201
|
+
void *ctx;
|
202
|
+
void (*ctx_free)(void*);
|
205
203
|
} *gqlDoc;
|
206
204
|
|
207
205
|
extern int gql_init(agooErr err);
|
@@ -222,8 +220,7 @@ extern gqlField gql_type_field(agooErr err,
|
|
222
220
|
gqlType return_type,
|
223
221
|
struct _gqlValue *default_value,
|
224
222
|
const char *desc,
|
225
|
-
size_t dlen
|
226
|
-
bool required);
|
223
|
+
size_t dlen);
|
227
224
|
|
228
225
|
extern gqlArg gql_field_arg(agooErr err,
|
229
226
|
gqlField field,
|
@@ -231,8 +228,7 @@ extern gqlArg gql_field_arg(agooErr err,
|
|
231
228
|
gqlType type,
|
232
229
|
const char *desc,
|
233
230
|
size_t dlen,
|
234
|
-
struct _gqlValue *def_value
|
235
|
-
bool required);
|
231
|
+
struct _gqlValue *def_value);
|
236
232
|
|
237
233
|
extern gqlArg gql_input_arg(agooErr err,
|
238
234
|
gqlType input,
|
@@ -240,8 +236,7 @@ extern gqlArg gql_input_arg(agooErr err,
|
|
240
236
|
gqlType type,
|
241
237
|
const char *desc,
|
242
238
|
size_t dlen,
|
243
|
-
struct _gqlValue *def_value
|
244
|
-
bool required);
|
239
|
+
struct _gqlValue *def_value);
|
245
240
|
|
246
241
|
extern gqlType gql_scalar_create(agooErr err, const char *name, const char *desc, size_t dlen);
|
247
242
|
|
@@ -252,8 +247,7 @@ extern gqlArg gql_dir_arg(agooErr err,
|
|
252
247
|
gqlType type,
|
253
248
|
const char *desc,
|
254
249
|
size_t dlen,
|
255
|
-
struct _gqlValue *def_value
|
256
|
-
bool required);
|
250
|
+
struct _gqlValue *def_value);
|
257
251
|
extern int gql_directive_on(agooErr err, gqlDir d, const char *on, int len);
|
258
252
|
extern gqlDir gql_directive_get(const char *name);
|
259
253
|
|
@@ -266,7 +260,8 @@ extern int gql_union_add(agooErr err, gqlType type, gqlType member);
|
|
266
260
|
extern gqlType gql_enum_create(agooErr err, const char *name, const char *desc, size_t dlen);
|
267
261
|
extern gqlEnumVal gql_enum_append(agooErr err, gqlType type, const char *value, size_t len, const char *desc, size_t dlen);
|
268
262
|
|
269
|
-
extern gqlType gql_assure_list(agooErr err, gqlType base
|
263
|
+
extern gqlType gql_assure_list(agooErr err, gqlType base);
|
264
|
+
extern gqlType gql_assure_nonnull(agooErr err, gqlType base);
|
270
265
|
|
271
266
|
extern int gql_type_set(agooErr err, gqlType type);
|
272
267
|
extern gqlType gql_type_get(const char *name);
|
@@ -291,6 +286,7 @@ extern agooText gql_doc_sdl(gqlDoc doc, agooText text);
|
|
291
286
|
extern void gql_dump_hook(struct _agooReq *req);
|
292
287
|
extern void gql_eval_get_hook(struct _agooReq *req);
|
293
288
|
extern void gql_eval_post_hook(struct _agooReq *req);
|
289
|
+
extern void gql_eval_options_hook(struct _agooReq *req);
|
294
290
|
|
295
291
|
extern int gql_validate(agooErr err);
|
296
292
|
|
data/ext/agoo/req.c
CHANGED
@@ -14,7 +14,7 @@ agooReq
|
|
14
14
|
agoo_req_create(size_t mlen) {
|
15
15
|
size_t size = mlen + sizeof(struct _agooReq) - 7;
|
16
16
|
agooReq req = (agooReq)AGOO_MALLOC(size);
|
17
|
-
|
17
|
+
|
18
18
|
if (NULL != req) {
|
19
19
|
memset(req, 0, size);
|
20
20
|
req->env = agoo_server.env_nil_value;
|
@@ -56,7 +56,7 @@ agoo_req_port(agooReq r) {
|
|
56
56
|
int len;
|
57
57
|
const char *host;
|
58
58
|
const char *colon;
|
59
|
-
|
59
|
+
|
60
60
|
if (NULL == (host = agoo_con_header_value(r->header.start, r->header.len, "Host", &len))) {
|
61
61
|
return 0;
|
62
62
|
}
|
@@ -94,7 +94,7 @@ agoo_req_query_value(agooReq r, const char *key, int klen, int *vlenp) {
|
|
94
94
|
static int
|
95
95
|
hexVal(int c) {
|
96
96
|
int h = -1;
|
97
|
-
|
97
|
+
|
98
98
|
if ('0' <= c && c <= '9') {
|
99
99
|
h = c - '0';
|
100
100
|
} else if ('a' <= c && c <= 'f') {
|
@@ -110,12 +110,12 @@ agoo_req_query_decode(char *s, int len) {
|
|
110
110
|
char *sn = s;
|
111
111
|
char *so = s;
|
112
112
|
char *end = s + len;
|
113
|
-
|
113
|
+
|
114
114
|
while (so < end) {
|
115
115
|
if ('%' == *so) {
|
116
116
|
int n;
|
117
117
|
int c = 0;
|
118
|
-
|
118
|
+
|
119
119
|
so++;
|
120
120
|
if (0 > (c = hexVal(*so))) {
|
121
121
|
*sn++ = '%';
|
@@ -133,7 +133,7 @@ agoo_req_query_decode(char *s, int len) {
|
|
133
133
|
}
|
134
134
|
}
|
135
135
|
*sn = '\0';
|
136
|
-
|
136
|
+
|
137
137
|
return (int)(sn - s);
|
138
138
|
}
|
139
139
|
|
@@ -145,9 +145,9 @@ agoo_req_header_value(agooReq req, const char *key, int *vlen) {
|
|
145
145
|
const char *hend = h + req->header.len;
|
146
146
|
const char *value;
|
147
147
|
int klen = (int)strlen(key);
|
148
|
-
|
148
|
+
|
149
149
|
while (h < hend) {
|
150
|
-
if (0 ==
|
150
|
+
if (0 == strncasecmp(key, h, klen) && ':' == h[klen]) {
|
151
151
|
h += klen + 1;
|
152
152
|
for (; ' ' == *h; h++) {
|
153
153
|
}
|
@@ -155,7 +155,7 @@ agoo_req_header_value(agooReq req, const char *key, int *vlen) {
|
|
155
155
|
for (; '\r' != *h && '\0' != *h; h++) {
|
156
156
|
}
|
157
157
|
*vlen = (int)(h - value);
|
158
|
-
|
158
|
+
|
159
159
|
return value;
|
160
160
|
}
|
161
161
|
for (; h < hend; h++) {
|
@@ -167,4 +167,3 @@ agoo_req_header_value(agooReq req, const char *key, int *vlen) {
|
|
167
167
|
}
|
168
168
|
return NULL;
|
169
169
|
}
|
170
|
-
|
data/ext/agoo/rgraphql.c
CHANGED
@@ -13,6 +13,7 @@
|
|
13
13
|
#include "gqlvalue.h"
|
14
14
|
#include "graphql.h"
|
15
15
|
#include "pub.h"
|
16
|
+
#include "request.h"
|
16
17
|
#include "sdl.h"
|
17
18
|
#include "server.h"
|
18
19
|
|
@@ -27,13 +28,31 @@ typedef struct _typeClass {
|
|
27
28
|
const char *classname;
|
28
29
|
} *TypeClass;
|
29
30
|
|
31
|
+
typedef struct _bhArgs {
|
32
|
+
agooErr err;
|
33
|
+
agooReq req;
|
34
|
+
agooText headers;
|
35
|
+
} *bhArgs;
|
36
|
+
|
30
37
|
static VALUE graphql_class = Qundef;
|
31
38
|
static VALUE vroot = Qnil;
|
39
|
+
static VALUE build_headers_func = Qnil;
|
40
|
+
static VALUE arg_clas = Qnil;
|
41
|
+
static VALUE field_clas = Qnil;
|
42
|
+
static VALUE type_clas = Qnil;
|
43
|
+
|
44
|
+
static ID call_id;
|
32
45
|
|
33
46
|
static TypeClass type_class_map = NULL;
|
34
47
|
|
35
48
|
static int
|
36
|
-
make_ruby_use(agooErr
|
49
|
+
make_ruby_use(agooErr err,
|
50
|
+
VALUE root,
|
51
|
+
const char *method,
|
52
|
+
const char *type_name,
|
53
|
+
bool fresh,
|
54
|
+
gqlType schema_type,
|
55
|
+
const char *desc) {
|
37
56
|
gqlType type;
|
38
57
|
gqlDirUse use;
|
39
58
|
volatile VALUE v;
|
@@ -47,7 +66,7 @@ make_ruby_use(agooErr err, VALUE root, const char *method, const char *type_name
|
|
47
66
|
return agoo_err_set(err, AGOO_ERR_ARG, "Failed to find the '%s' type.", type_name);
|
48
67
|
}
|
49
68
|
if (fresh) {
|
50
|
-
if (NULL == gql_type_field(err, schema_type, method, type, NULL, desc, 0
|
69
|
+
if (NULL == gql_type_field(err, schema_type, method, type, NULL, desc, 0)) {
|
51
70
|
return err->code;
|
52
71
|
}
|
53
72
|
}
|
@@ -85,7 +104,7 @@ call_eval(VALUE x) {
|
|
85
104
|
|
86
105
|
static void*
|
87
106
|
protect_eval(void *x) {
|
88
|
-
rb_rescue2(call_eval, (VALUE)x, rescue_error, (VALUE)x, rb_eException, 0);
|
107
|
+
rb_rescue2(call_eval, (VALUE)x, rescue_error, (VALUE)x, rb_eException, (VALUE)0);
|
89
108
|
|
90
109
|
return NULL;
|
91
110
|
}
|
@@ -225,6 +244,9 @@ coerce(agooErr err, gqlRef ref, gqlType type) {
|
|
225
244
|
if (Qnil == (VALUE)ref) {
|
226
245
|
return gql_null_create(err);
|
227
246
|
}
|
247
|
+
if (NULL != type && GQL_NON_NULL == type->kind) {
|
248
|
+
type = type->base;
|
249
|
+
}
|
228
250
|
if (NULL == type) {
|
229
251
|
// This is really an error but make a best effort anyway.
|
230
252
|
switch (rb_type((VALUE)ref)) {
|
@@ -372,12 +394,25 @@ ref_type(gqlRef ref) {
|
|
372
394
|
return type;
|
373
395
|
}
|
374
396
|
|
397
|
+
static VALUE
|
398
|
+
make_plan(gqlSel sel) {
|
399
|
+
|
400
|
+
// TBD create a plan object that wraps the sel, create children as needed
|
401
|
+
// plan is not valid outside of method
|
402
|
+
// should be able to create SDL from it
|
403
|
+
|
404
|
+
return Qnil;
|
405
|
+
}
|
406
|
+
|
375
407
|
static int
|
376
408
|
resolve(agooErr err, gqlDoc doc, gqlRef target, gqlField field, gqlSel sel, gqlValue result, int depth) {
|
377
409
|
volatile VALUE child;
|
410
|
+
volatile VALUE rreq = Qnil;
|
378
411
|
VALUE obj = (VALUE)target;
|
379
412
|
int d2 = depth + 1;
|
380
413
|
const char *key = sel->name;
|
414
|
+
ID method;
|
415
|
+
int arity;
|
381
416
|
|
382
417
|
if ('_' == *sel->name && '_' == sel->name[1]) {
|
383
418
|
if (0 == strcmp("__typename", sel->name)) {
|
@@ -397,8 +432,10 @@ resolve(agooErr err, gqlDoc doc, gqlRef target, gqlField field, gqlSel sel, gqlV
|
|
397
432
|
return agoo_err_set(err, AGOO_ERR_EVAL, "Not a valid operation on the root object.");
|
398
433
|
}
|
399
434
|
}
|
400
|
-
|
401
|
-
|
435
|
+
method = rb_intern(sel->name);
|
436
|
+
arity = rb_obj_method_arity(obj, method);
|
437
|
+
if (0 == arity) {
|
438
|
+
child = rb_funcall(obj, method, 0);
|
402
439
|
} else {
|
403
440
|
volatile VALUE rargs = rb_hash_new();
|
404
441
|
gqlSelArg sa;
|
@@ -429,7 +466,21 @@ resolve(agooErr err, gqlDoc doc, gqlRef target, gqlField field, gqlSel sel, gqlV
|
|
429
466
|
}
|
430
467
|
rb_hash_aset(rargs, rb_str_new_cstr(sa->name), gval_to_ruby(v));
|
431
468
|
}
|
432
|
-
|
469
|
+
if (-1 == arity || 1 == arity) {
|
470
|
+
child = rb_funcall(obj, method, 1, rargs);
|
471
|
+
} else {
|
472
|
+
if (NULL == doc->ctx) {
|
473
|
+
rreq = request_wrap(doc->req);
|
474
|
+
doc->ctx = (void*)rreq;
|
475
|
+
} else {
|
476
|
+
rreq = (VALUE)doc->ctx;
|
477
|
+
}
|
478
|
+
if (-2 == arity || 2 == arity) {
|
479
|
+
child = rb_funcall(obj, method, 2, rargs, rreq);
|
480
|
+
} else {
|
481
|
+
child = rb_funcall(obj, method, 3, rargs, rreq, make_plan(sel));
|
482
|
+
}
|
483
|
+
}
|
433
484
|
}
|
434
485
|
if (GQL_SUBSCRIPTION == doc->op->kind && RUBY_T_STRING == rb_type(child)) {
|
435
486
|
gqlValue c;
|
@@ -591,6 +642,7 @@ graphql_schema(VALUE self, VALUE root) {
|
|
591
642
|
gqlDirUse use;
|
592
643
|
gqlType schema_type;
|
593
644
|
bool fresh = false;
|
645
|
+
gqlType string_nn;
|
594
646
|
|
595
647
|
if (!rb_block_given_p()) {
|
596
648
|
rb_raise(rb_eStandardError, "A block is required.");
|
@@ -603,7 +655,8 @@ graphql_schema(VALUE self, VALUE root) {
|
|
603
655
|
printf("*-*-* %s\n", err.msg);
|
604
656
|
exit(2);
|
605
657
|
}
|
606
|
-
if (NULL ==
|
658
|
+
if (NULL == (string_nn = gql_assure_nonnull(&err, &gql_string_type)) ||
|
659
|
+
NULL == gql_dir_arg(&err, dir, "class", string_nn, NULL, 0, NULL)) {
|
607
660
|
printf("*-*-* %s\n", err.msg);
|
608
661
|
exit(3);
|
609
662
|
}
|
@@ -629,7 +682,7 @@ graphql_schema(VALUE self, VALUE root) {
|
|
629
682
|
printf("*-*-* %s\n", err.msg);
|
630
683
|
exit(6);
|
631
684
|
}
|
632
|
-
rb_rescue2(rescue_yield, Qnil, rescue_yield_error, (VALUE)&err, rb_eException, 0);
|
685
|
+
rb_rescue2(rescue_yield, Qnil, rescue_yield_error, (VALUE)&err, rb_eException, (VALUE)0);
|
633
686
|
if (AGOO_ERR_OK != err.code) {
|
634
687
|
printf("*-*-* %s\n", err.msg);
|
635
688
|
exit(7);
|
@@ -724,16 +777,16 @@ graphql_load_file(VALUE self, VALUE path) {
|
|
724
777
|
return Qnil;
|
725
778
|
}
|
726
779
|
|
727
|
-
/* Document-method:
|
780
|
+
/* Document-method: sdl_dump
|
728
781
|
*
|
729
|
-
* call-seq:
|
782
|
+
* call-seq: sdl_dump()
|
730
783
|
*
|
731
784
|
* The preferred method of inspecting a GraphQL schema is to use introspection
|
732
785
|
* queries but for debugging and for reviewing the schema a dump of the schema
|
733
|
-
* as SDL can be helpful. The _#
|
786
|
+
* as SDL can be helpful. The _#sdl_dump_ method returns the schema as an SDL
|
734
787
|
* string.
|
735
788
|
*
|
736
|
-
* - *options* [_Hash_]
|
789
|
+
* - *options* [_Hash_] options
|
737
790
|
*
|
738
791
|
* - *:with_description* [_true_|_false_] if true the description strings are included. If false they are not included.
|
739
792
|
*
|
@@ -767,6 +820,79 @@ graphql_sdl_dump(VALUE self, VALUE options) {
|
|
767
820
|
return dump;
|
768
821
|
}
|
769
822
|
|
823
|
+
static void
|
824
|
+
type_cb(gqlType type, void *ctx) {
|
825
|
+
VALUE rtypes = (VALUE)ctx;
|
826
|
+
VALUE t;
|
827
|
+
|
828
|
+
if (GQL_OBJECT != type->kind || type->core) {
|
829
|
+
return;
|
830
|
+
}
|
831
|
+
t = rb_obj_alloc(type_clas);
|
832
|
+
rb_ivar_set(t, rb_intern("@name"), rb_str_new_cstr(type->name));
|
833
|
+
if (NULL != type->desc) {
|
834
|
+
rb_ivar_set(t, rb_intern("@description"), rb_str_new_cstr(type->desc));
|
835
|
+
}
|
836
|
+
if (NULL != type->fields) {
|
837
|
+
VALUE fields = rb_ary_new();
|
838
|
+
VALUE field;
|
839
|
+
gqlField f;
|
840
|
+
|
841
|
+
rb_ivar_set(t, rb_intern("@fields"), fields);
|
842
|
+
for (f = type->fields; NULL != f; f = f->next) {
|
843
|
+
field = rb_obj_alloc(field_clas);
|
844
|
+
rb_ary_push(fields, field);
|
845
|
+
rb_ivar_set(field, rb_intern("@name"), rb_str_new_cstr(f->name));
|
846
|
+
if (NULL != f->desc) {
|
847
|
+
rb_ivar_set(field, rb_intern("@description"), rb_str_new_cstr(f->desc));
|
848
|
+
}
|
849
|
+
if (NULL != f->type) {
|
850
|
+
rb_ivar_set(field, rb_intern("@type_name"), rb_str_new_cstr(f->type->name));
|
851
|
+
}
|
852
|
+
if (NULL != f->default_value) {
|
853
|
+
rb_ivar_set(field, rb_intern("@default_value"), gval_to_ruby(f->default_value));
|
854
|
+
}
|
855
|
+
if (NULL != f->args) {
|
856
|
+
VALUE args = rb_ary_new();
|
857
|
+
VALUE arg;
|
858
|
+
gqlArg a;
|
859
|
+
|
860
|
+
rb_ivar_set(field, rb_intern("@args"), args);
|
861
|
+
for (a = f->args; NULL != a; a = a->next) {
|
862
|
+
arg = rb_obj_alloc(arg_clas);
|
863
|
+
rb_ary_push(args, arg);
|
864
|
+
rb_ivar_set(arg, rb_intern("@name"), rb_str_new_cstr(a->name));
|
865
|
+
if (NULL != a->desc) {
|
866
|
+
rb_ivar_set(arg, rb_intern("@description"), rb_str_new_cstr(a->desc));
|
867
|
+
}
|
868
|
+
if (NULL != a->type) {
|
869
|
+
rb_ivar_set(arg, rb_intern("@type_name"), rb_str_new_cstr(a->type->name));
|
870
|
+
}
|
871
|
+
if (NULL != a->default_value) {
|
872
|
+
rb_ivar_set(arg, rb_intern("@default_value"), gval_to_ruby(a->default_value));
|
873
|
+
}
|
874
|
+
}
|
875
|
+
}
|
876
|
+
}
|
877
|
+
}
|
878
|
+
rb_ary_push(rtypes, t);
|
879
|
+
}
|
880
|
+
|
881
|
+
/* Document-method: sdl_types
|
882
|
+
*
|
883
|
+
* call-seq: sdl_types()
|
884
|
+
*
|
885
|
+
* Returns an array of all SDL types as Ruby objects.
|
886
|
+
*/
|
887
|
+
static VALUE
|
888
|
+
graphql_sdl_types(VALUE self) {
|
889
|
+
VALUE rtypes = rb_ary_new();
|
890
|
+
|
891
|
+
gql_type_iterate(type_cb, (void*)rtypes);
|
892
|
+
|
893
|
+
return rtypes;
|
894
|
+
}
|
895
|
+
|
770
896
|
/* Document-method: publish
|
771
897
|
*
|
772
898
|
* call-seq: publish(subject, event)
|
@@ -791,6 +917,105 @@ graphql_publish(VALUE self, VALUE subject, VALUE event) {
|
|
791
917
|
return Qnil;
|
792
918
|
}
|
793
919
|
|
920
|
+
static VALUE
|
921
|
+
rescue_build_header(VALUE x, VALUE ignore) {
|
922
|
+
bhArgs args = (bhArgs)x;
|
923
|
+
volatile VALUE info = rb_errinfo();
|
924
|
+
volatile VALUE msg = rb_funcall(info, rb_intern("message"), 0);
|
925
|
+
|
926
|
+
agoo_err_set(args->err, AGOO_ERR_EVAL, "%s", rb_string_value_ptr(&msg));
|
927
|
+
|
928
|
+
return Qnil;
|
929
|
+
}
|
930
|
+
|
931
|
+
static int
|
932
|
+
build_headers_cb(VALUE key, VALUE value, VALUE x) {
|
933
|
+
bhArgs args = (bhArgs)x;
|
934
|
+
const char *ks = rb_string_value_ptr((VALUE*)&key);
|
935
|
+
volatile VALUE vs = rb_obj_as_string(value);
|
936
|
+
const char *s = rb_string_value_ptr((VALUE*)&vs);
|
937
|
+
|
938
|
+
if (NULL == (args->headers = gql_add_header(args->err, args->headers, ks, s))) {
|
939
|
+
rb_raise(rb_eStandardError, "%s", args->err->msg);
|
940
|
+
}
|
941
|
+
return ST_CONTINUE;
|
942
|
+
}
|
943
|
+
|
944
|
+
static VALUE
|
945
|
+
inner_build_headers(VALUE x) {
|
946
|
+
volatile VALUE hh = rb_funcall(build_headers_func, call_id, 1, request_wrap(((bhArgs)x)->req));
|
947
|
+
|
948
|
+
rb_hash_foreach(hh, build_headers_cb, x);
|
949
|
+
|
950
|
+
return Qnil;
|
951
|
+
}
|
952
|
+
|
953
|
+
static void*
|
954
|
+
protected_build_headers(void *x) {
|
955
|
+
return (void*)rb_rescue2(inner_build_headers, (VALUE)x, rescue_build_header, (VALUE)x, rb_eException, (VALUE)0);
|
956
|
+
}
|
957
|
+
|
958
|
+
static agooText
|
959
|
+
build_headers(agooErr err, agooReq req, agooText headers) {
|
960
|
+
struct _bhArgs args = {
|
961
|
+
.err = err,
|
962
|
+
.req = req,
|
963
|
+
.headers = headers,
|
964
|
+
};
|
965
|
+
rb_thread_call_with_gvl(protected_build_headers, &args);
|
966
|
+
|
967
|
+
return args.headers;
|
968
|
+
}
|
969
|
+
|
970
|
+
/* Document-method: build_headers=
|
971
|
+
*
|
972
|
+
* call-seq: build_headers=(func)
|
973
|
+
*
|
974
|
+
* Provide a function to call that builds headers for GraphQL responses. The
|
975
|
+
* function should expect a single request and should return a Hash of the
|
976
|
+
* headers to add. Content-Type and Content-Length should not be set.
|
977
|
+
*/
|
978
|
+
static VALUE
|
979
|
+
graphql_build_headers(VALUE self, VALUE func) {
|
980
|
+
gql_build_headers = build_headers;
|
981
|
+
build_headers_func = func;
|
982
|
+
rb_gc_register_address(&build_headers_func);
|
983
|
+
|
984
|
+
return Qnil;
|
985
|
+
}
|
986
|
+
|
987
|
+
static int
|
988
|
+
headers_cb(VALUE key, VALUE value, VALUE x) {
|
989
|
+
agooText *tp = (agooText*)x;
|
990
|
+
const char *ks = rb_string_value_ptr((VALUE*)&key);
|
991
|
+
volatile VALUE vs = rb_obj_as_string(value);
|
992
|
+
const char *s = rb_string_value_ptr((VALUE*)&vs);
|
993
|
+
struct _agooErr err = AGOO_ERR_INIT;
|
994
|
+
|
995
|
+
if (NULL == (*tp = gql_add_header(&err, *tp, ks, s))) {
|
996
|
+
rb_raise(rb_eStandardError, "%s", err.msg);
|
997
|
+
}
|
998
|
+
return ST_CONTINUE;
|
999
|
+
}
|
1000
|
+
|
1001
|
+
|
1002
|
+
/* Document-method: headers
|
1003
|
+
*
|
1004
|
+
* call-seq: headers(header_hash)
|
1005
|
+
*
|
1006
|
+
* Provide a Hash to be used as the headers for GraphQL responses.
|
1007
|
+
* Content-Type and Content-Length should not be set.
|
1008
|
+
*/
|
1009
|
+
static VALUE
|
1010
|
+
graphql_headers(VALUE self, VALUE map) {
|
1011
|
+
agooText t = agoo_text_allocate(1024);
|
1012
|
+
|
1013
|
+
rb_hash_foreach(map, headers_cb, (VALUE)&t);
|
1014
|
+
gql_headers = t;
|
1015
|
+
|
1016
|
+
return Qnil;
|
1017
|
+
}
|
1018
|
+
|
794
1019
|
/* Document-class: Agoo::Graphql
|
795
1020
|
*
|
796
1021
|
* The Agoo::GraphQL class provides support for the GraphQL API as defined in
|
@@ -814,5 +1039,16 @@ graphql_init(VALUE mod) {
|
|
814
1039
|
|
815
1040
|
rb_define_module_function(graphql_class, "sdl_dump", graphql_sdl_dump, 1);
|
816
1041
|
|
1042
|
+
rb_define_module_function(graphql_class, "sdl_types", graphql_sdl_types, 0);
|
1043
|
+
|
817
1044
|
rb_define_module_function(graphql_class, "publish", graphql_publish, 2);
|
1045
|
+
|
1046
|
+
rb_define_module_function(graphql_class, "build_headers=", graphql_build_headers, 1);
|
1047
|
+
rb_define_module_function(graphql_class, "headers", graphql_headers, 1);
|
1048
|
+
|
1049
|
+
arg_clas = rb_const_get_at(graphql_class, rb_intern("Arg"));
|
1050
|
+
field_clas = rb_const_get_at(graphql_class, rb_intern("Field"));
|
1051
|
+
type_clas = rb_const_get_at(graphql_class, rb_intern("Type"));
|
1052
|
+
|
1053
|
+
call_id = rb_intern("call");
|
818
1054
|
}
|