agoo 2.7.0 → 2.8.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of agoo might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/ext/agoo/agoo.c +25 -20
- data/ext/agoo/con.c +35 -35
- data/ext/agoo/error_stream.c +10 -8
- data/ext/agoo/gqlcobj.c +25 -0
- data/ext/agoo/gqlcobj.h +14 -0
- data/ext/agoo/gqleval.c +24 -11
- data/ext/agoo/gqleval.h +2 -0
- data/ext/agoo/gqlintro.c +30 -54
- data/ext/agoo/gqljson.c +36 -32
- data/ext/agoo/gqlvalue.c +105 -52
- data/ext/agoo/gqlvalue.h +3 -0
- data/ext/agoo/graphql.c +110 -80
- data/ext/agoo/graphql.h +17 -13
- data/ext/agoo/log.c +16 -12
- data/ext/agoo/rack_logger.c +4 -1
- data/ext/agoo/request.c +7 -9
- data/ext/agoo/rgraphql.c +41 -30
- data/ext/agoo/rresponse.c +7 -6
- data/ext/agoo/rserver.c +35 -22
- data/ext/agoo/sdl.c +234 -117
- data/ext/agoo/server.c +5 -5
- data/ext/agoo/text.c +23 -9
- data/lib/agoo/version.rb +1 -1
- data/test/graphql_test.rb +33 -27
- metadata +2 -2
data/ext/agoo/gqlvalue.c
CHANGED
@@ -34,7 +34,7 @@ static agooText
|
|
34
34
|
int_to_text(agooText text, gqlValue value, int indent, int depth) {
|
35
35
|
char num[32];
|
36
36
|
int cnt;
|
37
|
-
|
37
|
+
|
38
38
|
cnt = snprintf(num, sizeof(num), "%lld", (long long)value->i);
|
39
39
|
|
40
40
|
return agoo_text_append(text, num, cnt);
|
@@ -56,7 +56,7 @@ static agooText
|
|
56
56
|
i64_to_text(agooText text, gqlValue value, int indent, int depth) {
|
57
57
|
char num[32];
|
58
58
|
int cnt;
|
59
|
-
|
59
|
+
|
60
60
|
cnt = snprintf(num, sizeof(num), "%lld", (long long)value->i64);
|
61
61
|
|
62
62
|
return agoo_text_append(text, num, cnt);
|
@@ -132,6 +132,18 @@ struct _gqlType gql_token_type = {
|
|
132
132
|
.to_sdl = token_to_text,
|
133
133
|
};
|
134
134
|
|
135
|
+
// ID type
|
136
|
+
struct _gqlType gql_id_type = {
|
137
|
+
.name = "ID",
|
138
|
+
.desc = "ID scalar.",
|
139
|
+
.kind = GQL_SCALAR,
|
140
|
+
.scalar_kind = GQL_SCALAR_ID,
|
141
|
+
.core = true,
|
142
|
+
.destroy = string_destroy,
|
143
|
+
.to_json = string_to_text,
|
144
|
+
.to_sdl = string_to_text,
|
145
|
+
};
|
146
|
+
|
135
147
|
// Variable type ($var)
|
136
148
|
static agooText
|
137
149
|
var_to_text(agooText text, gqlValue value, int indent, int depth) {
|
@@ -185,7 +197,7 @@ static agooText
|
|
185
197
|
float_to_text(agooText text, gqlValue value, int indent, int depth) {
|
186
198
|
char num[32];
|
187
199
|
int cnt;
|
188
|
-
|
200
|
+
|
189
201
|
cnt = snprintf(num, sizeof(num), "%g", value->f);
|
190
202
|
|
191
203
|
return agoo_text_append(text, num, cnt);
|
@@ -235,7 +247,7 @@ read_zone(const char *s, int *vp) {
|
|
235
247
|
return NULL;
|
236
248
|
}
|
237
249
|
*vp = hr * 60 + min;
|
238
|
-
|
250
|
+
|
239
251
|
return s;
|
240
252
|
}
|
241
253
|
|
@@ -248,7 +260,7 @@ time_parse(agooErr err, const char *str, int len) {
|
|
248
260
|
uint64_t nsecs = 0;
|
249
261
|
int i = 9;
|
250
262
|
int64_t secs;
|
251
|
-
|
263
|
+
|
252
264
|
if (0 > len) {
|
253
265
|
len = (int)strlen(str);
|
254
266
|
}
|
@@ -309,7 +321,7 @@ time_parse(agooErr err, const char *str, int len) {
|
|
309
321
|
// fall through
|
310
322
|
case '+': {
|
311
323
|
int v = 0;
|
312
|
-
|
324
|
+
|
313
325
|
if (NULL == (s = read_zone(s, &v))) {
|
314
326
|
agoo_err_set(err, AGOO_ERR_PARSE, "Invalid time format.");
|
315
327
|
return 0;
|
@@ -397,7 +409,7 @@ time_parse(agooErr err, const char *str, int len) {
|
|
397
409
|
if (end <= s) {
|
398
410
|
agoo_err_set(err, AGOO_ERR_PARSE, "Invalid time format.");
|
399
411
|
return 0;
|
400
|
-
}
|
412
|
+
}
|
401
413
|
if ('0' <= *s && *s <= '9') {
|
402
414
|
nsecs = nsecs * 10 + *s - '0';
|
403
415
|
} else {
|
@@ -463,7 +475,7 @@ time_to_text(agooText text, gqlValue value, int indent, int depth) {
|
|
463
475
|
}
|
464
476
|
agoo_sectime(t, &at);
|
465
477
|
cnt = sprintf(str, "\"%04d-%02d-%02dT%02d:%02d:%02d.%09ldZ\"", at.year, at.mon, at.day, at.hour, at.min, at.sec, (long)nsecs);
|
466
|
-
|
478
|
+
|
467
479
|
return agoo_text_append(text, str, cnt);
|
468
480
|
}
|
469
481
|
|
@@ -482,7 +494,7 @@ struct _gqlType gql_time_type = {
|
|
482
494
|
static int
|
483
495
|
hexVal(int c) {
|
484
496
|
int h = -1;
|
485
|
-
|
497
|
+
|
486
498
|
if ('0' <= c && c <= '9') {
|
487
499
|
h = c - '0';
|
488
500
|
} else if ('a' <= c && c <= 'f') {
|
@@ -500,7 +512,7 @@ parse_uuid(agooErr err, const char *str, int len, uint64_t *hip, uint64_t *lop)
|
|
500
512
|
uint64_t lo = 0;
|
501
513
|
int i;
|
502
514
|
int n;
|
503
|
-
|
515
|
+
|
504
516
|
if (0 >= len) {
|
505
517
|
len = (int)strlen(str);
|
506
518
|
}
|
@@ -679,7 +691,7 @@ gql_object_to_json(agooText text, gqlValue value, int indent, int depth) {
|
|
679
691
|
int i2 = i + indent;
|
680
692
|
int d2 = depth + 1;
|
681
693
|
gqlLink link;
|
682
|
-
|
694
|
+
|
683
695
|
if (0 < indent) {
|
684
696
|
i++; // for \n
|
685
697
|
i2++;
|
@@ -719,7 +731,7 @@ gql_object_to_sdl(agooText text, gqlValue value, int indent, int depth) {
|
|
719
731
|
int i2 = i + indent;
|
720
732
|
int d2 = depth + 1;
|
721
733
|
gqlLink link;
|
722
|
-
|
734
|
+
|
723
735
|
if (0 < indent) {
|
724
736
|
i++; // for \n
|
725
737
|
i2++;
|
@@ -772,7 +784,6 @@ gql_value_destroy(gqlValue value) {
|
|
772
784
|
value->type->destroy(value);
|
773
785
|
}
|
774
786
|
} else if (GQL_ENUM == value->type->kind) {
|
775
|
-
// TBD destroy string
|
776
787
|
string_destroy(value);
|
777
788
|
} else {
|
778
789
|
return;
|
@@ -789,6 +800,7 @@ gql_value_init(agooErr err) {
|
|
789
800
|
AGOO_ERR_OK != gql_type_set(err, &gql_float_type) ||
|
790
801
|
AGOO_ERR_OK != gql_type_set(err, &gql_time_type) ||
|
791
802
|
AGOO_ERR_OK != gql_type_set(err, &gql_uuid_type) ||
|
803
|
+
AGOO_ERR_OK != gql_type_set(err, &gql_id_type) ||
|
792
804
|
AGOO_ERR_OK != gql_type_set(err, &gql_string_type)) {
|
793
805
|
return err->code;
|
794
806
|
}
|
@@ -808,9 +820,8 @@ gql_i64_set(gqlValue value, int64_t i) {
|
|
808
820
|
value->i64 = i;
|
809
821
|
}
|
810
822
|
|
811
|
-
int
|
812
|
-
|
813
|
-
value->type = &gql_string_type;
|
823
|
+
static int
|
824
|
+
string_set(agooErr err, gqlValue value, const char *str, int len) {
|
814
825
|
if (NULL == str) {
|
815
826
|
value->str.alloced = true;
|
816
827
|
value->str.ptr = NULL;
|
@@ -831,27 +842,25 @@ gql_string_set(agooErr err, gqlValue value, const char *str, int len) {
|
|
831
842
|
return AGOO_ERR_OK;
|
832
843
|
}
|
833
844
|
|
845
|
+
int
|
846
|
+
gql_string_set(agooErr err, gqlValue value, const char *str, int len) {
|
847
|
+
value->type = &gql_string_type;
|
848
|
+
|
849
|
+
return string_set(err, value, str, len);
|
850
|
+
}
|
851
|
+
|
834
852
|
int
|
835
853
|
gql_token_set(agooErr err, gqlValue value, const char *str, int len) {
|
836
854
|
value->type = &gql_token_type;
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
value->str.alloced = false;
|
847
|
-
} else {
|
848
|
-
value->str.alloced = true;
|
849
|
-
if (NULL == (value->str.ptr = AGOO_STRNDUP(str, len))) {
|
850
|
-
return AGOO_ERR_MEM(err, "strndup()");
|
851
|
-
}
|
852
|
-
}
|
853
|
-
}
|
854
|
-
return AGOO_ERR_OK;
|
855
|
+
|
856
|
+
return string_set(err, value, str, len);
|
857
|
+
}
|
858
|
+
|
859
|
+
int
|
860
|
+
gql_id_set(agooErr err, gqlValue value, const char *str, int len) {
|
861
|
+
value->type = &gql_id_type;
|
862
|
+
|
863
|
+
return string_set(err, value, str, len);
|
855
864
|
}
|
856
865
|
|
857
866
|
void
|
@@ -989,7 +998,7 @@ gql_object_set(agooErr err, gqlValue obj, const char *key, gqlValue item) {
|
|
989
998
|
static gqlValue
|
990
999
|
value_create(gqlType type) {
|
991
1000
|
gqlValue v = (gqlValue)AGOO_CALLOC(1, sizeof(struct _gqlValue));
|
992
|
-
|
1001
|
+
|
993
1002
|
if (NULL != v) {
|
994
1003
|
v->type = type;
|
995
1004
|
}
|
@@ -999,7 +1008,7 @@ value_create(gqlType type) {
|
|
999
1008
|
gqlValue
|
1000
1009
|
gql_int_create(agooErr err, int32_t i) {
|
1001
1010
|
gqlValue v = value_create(&gql_int_type);
|
1002
|
-
|
1011
|
+
|
1003
1012
|
if (NULL != v) {
|
1004
1013
|
v->i = i;
|
1005
1014
|
}
|
@@ -1009,7 +1018,7 @@ gql_int_create(agooErr err, int32_t i) {
|
|
1009
1018
|
gqlValue
|
1010
1019
|
gql_i64_create(agooErr err, int64_t i) {
|
1011
1020
|
gqlValue v = value_create(&gql_i64_type);
|
1012
|
-
|
1021
|
+
|
1013
1022
|
if (NULL != v) {
|
1014
1023
|
v->i64 = i;
|
1015
1024
|
}
|
@@ -1019,7 +1028,7 @@ gql_i64_create(agooErr err, int64_t i) {
|
|
1019
1028
|
gqlValue
|
1020
1029
|
gql_string_create(agooErr err, const char *str, int len) {
|
1021
1030
|
gqlValue v;
|
1022
|
-
|
1031
|
+
|
1023
1032
|
if (0 >= len) {
|
1024
1033
|
len = (int)strlen(str);
|
1025
1034
|
}
|
@@ -1042,7 +1051,7 @@ gql_string_create(agooErr err, const char *str, int len) {
|
|
1042
1051
|
gqlValue
|
1043
1052
|
gql_token_create(agooErr err, const char *str, int len, gqlType type) {
|
1044
1053
|
gqlValue v;
|
1045
|
-
|
1054
|
+
|
1046
1055
|
if (0 >= len) {
|
1047
1056
|
len = (int)strlen(str);
|
1048
1057
|
}
|
@@ -1065,10 +1074,33 @@ gql_token_create(agooErr err, const char *str, int len, gqlType type) {
|
|
1065
1074
|
return v;
|
1066
1075
|
}
|
1067
1076
|
|
1077
|
+
gqlValue
|
1078
|
+
gql_id_create(agooErr err, const char *str, int len) {
|
1079
|
+
gqlValue v;
|
1080
|
+
|
1081
|
+
if (0 >= len) {
|
1082
|
+
len = (int)strlen(str);
|
1083
|
+
}
|
1084
|
+
if (NULL != (v = value_create(&gql_id_type))) {
|
1085
|
+
if ((int)sizeof(v->str.a) <= len) {
|
1086
|
+
v->str.alloced = true;
|
1087
|
+
if (NULL == (v->str.ptr = AGOO_STRNDUP(str, len))) {
|
1088
|
+
AGOO_ERR_MEM(err, "strdup()");
|
1089
|
+
return NULL;
|
1090
|
+
}
|
1091
|
+
} else {
|
1092
|
+
v->str.alloced = false;
|
1093
|
+
strncpy(v->str.a, str, len);
|
1094
|
+
v->str.a[len] = '\0';
|
1095
|
+
}
|
1096
|
+
}
|
1097
|
+
return v;
|
1098
|
+
}
|
1099
|
+
|
1068
1100
|
gqlValue
|
1069
1101
|
gql_var_create(agooErr err, const char *str, int len) {
|
1070
1102
|
gqlValue v;
|
1071
|
-
|
1103
|
+
|
1072
1104
|
if (0 >= len) {
|
1073
1105
|
len = (int)strlen(str);
|
1074
1106
|
}
|
@@ -1091,7 +1123,7 @@ gql_var_create(agooErr err, const char *str, int len) {
|
|
1091
1123
|
gqlValue
|
1092
1124
|
gql_bool_create(agooErr err, bool b) {
|
1093
1125
|
gqlValue v = value_create(&gql_bool_type);
|
1094
|
-
|
1126
|
+
|
1095
1127
|
if (NULL != v) {
|
1096
1128
|
v->b = b;
|
1097
1129
|
}
|
@@ -1101,7 +1133,7 @@ gql_bool_create(agooErr err, bool b) {
|
|
1101
1133
|
gqlValue
|
1102
1134
|
gql_float_create(agooErr err, double f) {
|
1103
1135
|
gqlValue v = value_create(&gql_float_type);
|
1104
|
-
|
1136
|
+
|
1105
1137
|
if (NULL != v) {
|
1106
1138
|
v->f = f;
|
1107
1139
|
}
|
@@ -1111,7 +1143,7 @@ gql_float_create(agooErr err, double f) {
|
|
1111
1143
|
gqlValue
|
1112
1144
|
gql_time_create(agooErr err, int64_t t) {
|
1113
1145
|
gqlValue v = value_create(&gql_time_type);
|
1114
|
-
|
1146
|
+
|
1115
1147
|
if (NULL != v) {
|
1116
1148
|
v->time = t;
|
1117
1149
|
}
|
@@ -1121,7 +1153,7 @@ gql_time_create(agooErr err, int64_t t) {
|
|
1121
1153
|
gqlValue
|
1122
1154
|
gql_time_str_create(agooErr err, const char *str, int len) {
|
1123
1155
|
gqlValue v = value_create(&gql_time_type);
|
1124
|
-
|
1156
|
+
|
1125
1157
|
if (NULL != v) {
|
1126
1158
|
if (0 >= len) {
|
1127
1159
|
len = (int)strlen(str);
|
@@ -1134,7 +1166,7 @@ gql_time_str_create(agooErr err, const char *str, int len) {
|
|
1134
1166
|
gqlValue
|
1135
1167
|
gql_uuid_create(agooErr err, uint64_t hi, uint64_t lo) {
|
1136
1168
|
gqlValue v = value_create(&gql_uuid_type);
|
1137
|
-
|
1169
|
+
|
1138
1170
|
if (NULL != v) {
|
1139
1171
|
v->uuid.hi = hi;
|
1140
1172
|
v->uuid.lo = lo;
|
@@ -1162,7 +1194,7 @@ gql_uuid_str_create(agooErr err, const char *str, int len) {
|
|
1162
1194
|
gqlValue
|
1163
1195
|
gql_null_create(agooErr err) {
|
1164
1196
|
gqlValue v = value_create(&gql_null_type);
|
1165
|
-
|
1197
|
+
|
1166
1198
|
return v;
|
1167
1199
|
}
|
1168
1200
|
|
@@ -1225,7 +1257,7 @@ gql_string_get(gqlValue value) {
|
|
1225
1257
|
const char *s = NULL;
|
1226
1258
|
|
1227
1259
|
if (NULL != value) {
|
1228
|
-
if (&gql_string_type == value->type || &gql_token_type == value->type || &gql_var_type == value->type ||
|
1260
|
+
if (&gql_string_type == value->type || &gql_token_type == value->type || &gql_var_type == value->type || &gql_id_type == value->type ||
|
1229
1261
|
GQL_ENUM == value->type->kind) {
|
1230
1262
|
if (value->str.alloced) {
|
1231
1263
|
s = value->str.ptr;
|
@@ -1252,7 +1284,7 @@ convert_to_bool(agooErr err, gqlValue value) {
|
|
1252
1284
|
case GQL_SCALAR_STRING:
|
1253
1285
|
case GQL_SCALAR_TOKEN: {
|
1254
1286
|
const char *s = gql_string_get(value);
|
1255
|
-
|
1287
|
+
|
1256
1288
|
value->type = &gql_bool_type;
|
1257
1289
|
if (0 == strcasecmp("true", s)) {
|
1258
1290
|
value->b = true;
|
@@ -1392,7 +1424,7 @@ static int
|
|
1392
1424
|
convert_to_string(agooErr err, gqlValue value) {
|
1393
1425
|
char buf[64];
|
1394
1426
|
int cnt;
|
1395
|
-
|
1427
|
+
|
1396
1428
|
switch (value->type->scalar_kind) {
|
1397
1429
|
case GQL_SCALAR_BOOL:
|
1398
1430
|
if (value->b) {
|
@@ -1416,6 +1448,9 @@ convert_to_string(agooErr err, gqlValue value) {
|
|
1416
1448
|
case GQL_SCALAR_TOKEN:
|
1417
1449
|
value->type = &gql_string_type;
|
1418
1450
|
break;
|
1451
|
+
case GQL_SCALAR_ID:
|
1452
|
+
value->type = &gql_string_type;
|
1453
|
+
break;
|
1419
1454
|
case GQL_SCALAR_TIME: {
|
1420
1455
|
struct _agooTime at;
|
1421
1456
|
int64_t tt = value->time;
|
@@ -1450,6 +1485,7 @@ static int
|
|
1450
1485
|
convert_to_token(agooErr err, gqlValue value) {
|
1451
1486
|
switch (value->type->scalar_kind) {
|
1452
1487
|
case GQL_SCALAR_STRING:
|
1488
|
+
case GQL_SCALAR_ID:
|
1453
1489
|
value->type = &gql_token_type;
|
1454
1490
|
break;
|
1455
1491
|
default:
|
@@ -1459,6 +1495,20 @@ convert_to_token(agooErr err, gqlValue value) {
|
|
1459
1495
|
return err->code;
|
1460
1496
|
}
|
1461
1497
|
|
1498
|
+
static int
|
1499
|
+
convert_to_id(agooErr err, gqlValue value) {
|
1500
|
+
switch (value->type->scalar_kind) {
|
1501
|
+
case GQL_SCALAR_STRING:
|
1502
|
+
case GQL_SCALAR_TOKEN:
|
1503
|
+
value->type = &gql_id_type;
|
1504
|
+
break;
|
1505
|
+
default:
|
1506
|
+
agoo_err_set(err, AGOO_ERR_PARSE, "Can not coerce a %s into a ID value.", value->type->name);
|
1507
|
+
break;
|
1508
|
+
}
|
1509
|
+
return err->code;
|
1510
|
+
}
|
1511
|
+
|
1462
1512
|
static int
|
1463
1513
|
convert_to_time(agooErr err, gqlValue value) {
|
1464
1514
|
switch (value->type->scalar_kind) {
|
@@ -1489,7 +1539,7 @@ convert_to_uuid(agooErr err, gqlValue value) {
|
|
1489
1539
|
case GQL_SCALAR_STRING: {
|
1490
1540
|
const char *s = gql_string_get(value);
|
1491
1541
|
bool alloced = value->str.alloced;
|
1492
|
-
|
1542
|
+
|
1493
1543
|
if (AGOO_ERR_OK == gql_uuid_str_set(err, value, s, 0)) {
|
1494
1544
|
if (alloced) {
|
1495
1545
|
AGOO_FREE((char*)s);
|
@@ -1507,7 +1557,7 @@ convert_to_uuid(agooErr err, gqlValue value) {
|
|
1507
1557
|
int
|
1508
1558
|
gql_value_convert(agooErr err, gqlValue value, struct _gqlType *type) {
|
1509
1559
|
int code = AGOO_ERR_OK;
|
1510
|
-
|
1560
|
+
|
1511
1561
|
if (type != value->type) {
|
1512
1562
|
switch (type->scalar_kind) {
|
1513
1563
|
case GQL_SCALAR_BOOL:
|
@@ -1528,6 +1578,9 @@ gql_value_convert(agooErr err, gqlValue value, struct _gqlType *type) {
|
|
1528
1578
|
case GQL_SCALAR_TOKEN:
|
1529
1579
|
code = convert_to_token(err, value);
|
1530
1580
|
break;
|
1581
|
+
case GQL_SCALAR_ID:
|
1582
|
+
code = convert_to_id(err, value);
|
1583
|
+
break;
|
1531
1584
|
case GQL_SCALAR_TIME:
|
1532
1585
|
code = convert_to_time(err, value);
|
1533
1586
|
break;
|
@@ -1564,6 +1617,7 @@ gql_value_dup(agooErr err, gqlValue value) {
|
|
1564
1617
|
break;
|
1565
1618
|
case GQL_SCALAR_STRING:
|
1566
1619
|
case GQL_SCALAR_TOKEN:
|
1620
|
+
case GQL_SCALAR_ID:
|
1567
1621
|
if (value->str.alloced) {
|
1568
1622
|
if (NULL == (dup->str.ptr = strdup(value->str.ptr))) {
|
1569
1623
|
AGOO_ERR_MEM(err, "strdup()");
|
@@ -1586,4 +1640,3 @@ gql_value_dup(agooErr err, gqlValue value) {
|
|
1586
1640
|
}
|
1587
1641
|
return dup;
|
1588
1642
|
}
|
1589
|
-
|
data/ext/agoo/gqlvalue.h
CHANGED
@@ -58,6 +58,7 @@ extern void gql_link_destroy(gqlLink link);
|
|
58
58
|
extern gqlValue gql_int_create(agooErr err, int32_t i);
|
59
59
|
extern gqlValue gql_i64_create(agooErr err, int64_t i);
|
60
60
|
extern gqlValue gql_string_create(agooErr err, const char *str, int len);
|
61
|
+
extern gqlValue gql_id_create(agooErr err, const char *str, int len);
|
61
62
|
extern gqlValue gql_token_create(agooErr err, const char *str, int len, struct _gqlType *type);
|
62
63
|
extern gqlValue gql_var_create(agooErr err, const char *str, int len);
|
63
64
|
extern gqlValue gql_bool_create(agooErr err, bool b);
|
@@ -77,6 +78,7 @@ extern int gql_object_set(agooErr err, gqlValue obj, const char *key, gqlValue i
|
|
77
78
|
extern void gql_int_set(gqlValue value, int32_t i);
|
78
79
|
extern void gql_i64_set(gqlValue value, int64_t i);
|
79
80
|
extern int gql_string_set(agooErr err, gqlValue value, const char *str, int len);
|
81
|
+
extern int gql_id_set(agooErr err, gqlValue value, const char *str, int len);
|
80
82
|
extern int gql_token_set(agooErr err, gqlValue value, const char *str, int len);
|
81
83
|
extern void gql_bool_set(gqlValue value, bool b);
|
82
84
|
extern void gql_float_set(gqlValue value, double f);
|
@@ -105,6 +107,7 @@ extern struct _gqlType gql_time_type;
|
|
105
107
|
extern struct _gqlType gql_uuid_type;
|
106
108
|
extern struct _gqlType gql_string_type;
|
107
109
|
extern struct _gqlType gql_token_type; // used for enum values
|
110
|
+
extern struct _gqlType gql_id_type;
|
108
111
|
extern struct _gqlType gql_var_type; // used for variable keys
|
109
112
|
|
110
113
|
#endif // AGOO_GQLVALUE_H
|
data/ext/agoo/graphql.c
CHANGED
@@ -8,6 +8,7 @@
|
|
8
8
|
#include "graphql.h"
|
9
9
|
#include "gqlintro.h"
|
10
10
|
#include "gqlvalue.h"
|
11
|
+
#include "log.h"
|
11
12
|
#include "req.h"
|
12
13
|
#include "res.h"
|
13
14
|
|
@@ -46,7 +47,7 @@ static const char spaces[16] = " ";
|
|
46
47
|
|
47
48
|
gqlDir gql_directives = NULL;
|
48
49
|
|
49
|
-
static gqlType schema_type = NULL;
|
50
|
+
//static gqlType schema_type = NULL;
|
50
51
|
static bool inited = false;
|
51
52
|
|
52
53
|
static void gql_frag_destroy(gqlFrag frag);
|
@@ -75,13 +76,16 @@ static const char*
|
|
75
76
|
kind_string(gqlKind kind) {
|
76
77
|
switch (kind) {
|
77
78
|
case GQL_UNDEF: return "undefined";
|
79
|
+
case GQL_SCHEMA: return "schema";
|
78
80
|
case GQL_OBJECT: return "object";
|
81
|
+
case GQL_FRAG: return "fragment";
|
79
82
|
case GQL_INPUT: return "input";
|
80
83
|
case GQL_UNION: return "union";
|
81
84
|
case GQL_INTERFACE: return "interface";
|
82
85
|
case GQL_ENUM: return "enum";
|
83
86
|
case GQL_SCALAR: return "scalar";
|
84
87
|
case GQL_LIST: return "list";
|
88
|
+
case GQL_NON_NULL: return "non-null";
|
85
89
|
default: break;
|
86
90
|
}
|
87
91
|
return "unknown";
|
@@ -158,6 +162,7 @@ type_clean(gqlType type) {
|
|
158
162
|
type->dir = NULL;
|
159
163
|
|
160
164
|
switch (type->kind) {
|
165
|
+
case GQL_SCHEMA:
|
161
166
|
case GQL_OBJECT:
|
162
167
|
case GQL_INTERFACE: {
|
163
168
|
gqlField f;
|
@@ -218,6 +223,7 @@ type_destroy(gqlType type) {
|
|
218
223
|
&gql_uuid_type == type ||
|
219
224
|
&gql_token_type == type ||
|
220
225
|
&gql_var_type == type ||
|
226
|
+
&gql_id_type == type ||
|
221
227
|
&gql_string_type == type) {
|
222
228
|
|
223
229
|
return;
|
@@ -348,62 +354,6 @@ type_remove(gqlType type) {
|
|
348
354
|
}
|
349
355
|
}
|
350
356
|
|
351
|
-
int
|
352
|
-
gql_init(agooErr err) {
|
353
|
-
gqlType query_type;
|
354
|
-
gqlType mutation_type;
|
355
|
-
gqlType subscription_type;
|
356
|
-
|
357
|
-
if (inited) {
|
358
|
-
return AGOO_ERR_OK;
|
359
|
-
}
|
360
|
-
memset(buckets, 0, sizeof(buckets));
|
361
|
-
if (AGOO_ERR_OK != gql_value_init(err) ||
|
362
|
-
AGOO_ERR_OK != gql_intro_init(err)) {
|
363
|
-
|
364
|
-
return err->code;
|
365
|
-
}
|
366
|
-
if (NULL == (query_type = gql_type_create(err, "Query", "The GraphQL root Query.", 0, NULL)) ||
|
367
|
-
NULL == (mutation_type = gql_type_create(err, "Mutation", "The GraphQL root Mutation.", 0, NULL)) ||
|
368
|
-
NULL == (subscription_type = gql_type_create(err, "Subscription", "The GraphQL root Subscription.", 0, NULL)) ||
|
369
|
-
NULL == (schema_type = gql_type_create(err, "schema", "The GraphQL root Object.", 0, NULL)) ||
|
370
|
-
|
371
|
-
NULL == gql_type_field(err, schema_type, "query", query_type, NULL, "Root level query.", 0, false) ||
|
372
|
-
NULL == gql_type_field(err, schema_type, "mutation", mutation_type, NULL, "Root level mutation.", 0, false) ||
|
373
|
-
NULL == gql_type_field(err, schema_type, "subscription", subscription_type, NULL, "Root level subscription.", 0, false)) {
|
374
|
-
|
375
|
-
return err->code;
|
376
|
-
}
|
377
|
-
inited = true;
|
378
|
-
|
379
|
-
return AGOO_ERR_OK;
|
380
|
-
}
|
381
|
-
|
382
|
-
void
|
383
|
-
gql_destroy() {
|
384
|
-
Slot *sp = buckets;
|
385
|
-
Slot s;
|
386
|
-
Slot n;
|
387
|
-
int i;
|
388
|
-
gqlDir dir;
|
389
|
-
|
390
|
-
for (i = BUCKET_SIZE; 0 < i; i--, sp++) {
|
391
|
-
s = *sp;
|
392
|
-
|
393
|
-
*sp = NULL;
|
394
|
-
for (; NULL != s; s = n) {
|
395
|
-
n = s->next;
|
396
|
-
type_destroy(s->type);
|
397
|
-
AGOO_FREE(s);
|
398
|
-
}
|
399
|
-
}
|
400
|
-
while (NULL != (dir = gql_directives)) {
|
401
|
-
gql_directives = dir->next;
|
402
|
-
dir_destroy(dir);
|
403
|
-
}
|
404
|
-
inited = false;
|
405
|
-
}
|
406
|
-
|
407
357
|
static gqlType
|
408
358
|
type_create(agooErr err, gqlKind kind, const char *name, const char *desc, size_t dlen) {
|
409
359
|
gqlType type = gql_type_get(name);
|
@@ -438,10 +388,11 @@ type_create(agooErr err, gqlKind kind, const char *name, const char *desc, size_
|
|
438
388
|
}
|
439
389
|
type->kind = kind;
|
440
390
|
} else if (type->core) {
|
441
|
-
agoo_err_set(err, AGOO_ERR_LOCK, "%
|
391
|
+
agoo_err_set(err, AGOO_ERR_LOCK, "%s can not be modified.", name);
|
442
392
|
return NULL;
|
443
393
|
} else if (kind == type->kind) { // looks like it is being modified so remove all the old stuff
|
444
|
-
|
394
|
+
agoo_err_set(err, AGOO_ERR_LOCK, "%s already exists.", name);
|
395
|
+
return NULL;
|
445
396
|
} else {
|
446
397
|
agoo_err_set(err, AGOO_ERR_LOCK, "%d already exists as a %s.", name, kind_string(type->kind));
|
447
398
|
return NULL;
|
@@ -449,17 +400,65 @@ type_create(agooErr err, gqlKind kind, const char *name, const char *desc, size_
|
|
449
400
|
return type;
|
450
401
|
}
|
451
402
|
|
403
|
+
gqlType
|
404
|
+
gql_schema_create(agooErr err, const char *desc, size_t dlen) {
|
405
|
+
gqlType type = type_create(err, GQL_SCHEMA, "schema", desc, dlen);
|
406
|
+
|
407
|
+
if (NULL != type) {
|
408
|
+
type->fields = NULL;
|
409
|
+
type->interfaces = NULL;
|
410
|
+
}
|
411
|
+
return type;
|
412
|
+
}
|
413
|
+
|
414
|
+
int
|
415
|
+
gql_init(agooErr err) {
|
416
|
+
if (inited) {
|
417
|
+
return AGOO_ERR_OK;
|
418
|
+
}
|
419
|
+
memset(buckets, 0, sizeof(buckets));
|
420
|
+
if (AGOO_ERR_OK != gql_value_init(err) ||
|
421
|
+
AGOO_ERR_OK != gql_intro_init(err)) {
|
422
|
+
|
423
|
+
return err->code;
|
424
|
+
}
|
425
|
+
inited = true;
|
426
|
+
|
427
|
+
return AGOO_ERR_OK;
|
428
|
+
}
|
429
|
+
|
430
|
+
extern gqlType _gql_root_type;
|
431
|
+
void
|
432
|
+
gql_destroy() {
|
433
|
+
Slot *sp = buckets;
|
434
|
+
Slot s;
|
435
|
+
Slot n;
|
436
|
+
int i;
|
437
|
+
gqlDir dir;
|
438
|
+
|
439
|
+
for (i = BUCKET_SIZE; 0 < i; i--, sp++) {
|
440
|
+
s = *sp;
|
441
|
+
|
442
|
+
*sp = NULL;
|
443
|
+
for (; NULL != s; s = n) {
|
444
|
+
n = s->next;
|
445
|
+
type_destroy(s->type);
|
446
|
+
AGOO_FREE(s);
|
447
|
+
}
|
448
|
+
}
|
449
|
+
while (NULL != (dir = gql_directives)) {
|
450
|
+
gql_directives = dir->next;
|
451
|
+
dir_destroy(dir);
|
452
|
+
}
|
453
|
+
_gql_root_type = NULL;
|
454
|
+
inited = false;
|
455
|
+
}
|
456
|
+
|
452
457
|
static gqlType
|
453
458
|
type_undef_create(agooErr err, const char *name) {
|
454
459
|
return type_create(err, GQL_UNDEF, name, NULL, 0);
|
455
460
|
}
|
456
461
|
|
457
|
-
agooText
|
458
|
-
gql_object_to_graphql(agooText text, gqlValue value, int indent, int depth) {
|
459
|
-
// TBD
|
460
|
-
return text;
|
461
|
-
}
|
462
|
-
|
463
462
|
gqlType
|
464
463
|
gql_assure_type(agooErr err, const char *name) {
|
465
464
|
gqlType type = NULL;
|
@@ -679,9 +678,16 @@ gql_enum_create(agooErr err, const char *name, const char *desc, size_t dlen) {
|
|
679
678
|
|
680
679
|
gqlEnumVal
|
681
680
|
gql_enum_append(agooErr err, gqlType type, const char *value, size_t len, const char *desc, size_t dlen) {
|
682
|
-
gqlEnumVal
|
681
|
+
gqlEnumVal last = type->choices;
|
682
|
+
gqlEnumVal ev;
|
683
683
|
|
684
|
-
|
684
|
+
for (; NULL != last; last = last->next) {
|
685
|
+
if (0 == strcmp(value, last->value)) {
|
686
|
+
agoo_err_set(err, AGOO_ERR_TOO_MANY, "Enum %s already has a choice of %s.", type->name, value);
|
687
|
+
return NULL;
|
688
|
+
}
|
689
|
+
}
|
690
|
+
if (NULL == (ev = (gqlEnumVal)AGOO_MALLOC(sizeof(struct _gqlEnumVal)))) {
|
685
691
|
AGOO_ERR_MEM(err, "GraphQL Enum Value");
|
686
692
|
return NULL;
|
687
693
|
}
|
@@ -702,9 +708,7 @@ gql_enum_append(agooErr err, gqlType type, const char *value, size_t len, const
|
|
702
708
|
ev->next = type->choices;
|
703
709
|
type->choices = ev;
|
704
710
|
} else {
|
705
|
-
|
706
|
-
|
707
|
-
for (; NULL != last->next; last = last->next) {
|
711
|
+
for (last = type->choices; NULL != last->next; last = last->next) {
|
708
712
|
}
|
709
713
|
ev->next = NULL;
|
710
714
|
last->next = ev;
|
@@ -1038,6 +1042,18 @@ gql_type_sdl(agooText text, gqlType type, bool with_desc) {
|
|
1038
1042
|
desc_sdl(text, type->desc, 0);
|
1039
1043
|
}
|
1040
1044
|
switch (type->kind) {
|
1045
|
+
case GQL_SCHEMA: {
|
1046
|
+
gqlField f;
|
1047
|
+
|
1048
|
+
text = agoo_text_append(text, "schema", 6);
|
1049
|
+
text = append_dir_use(text, type->dir);
|
1050
|
+
text = agoo_text_append(text, " {\n", 3);
|
1051
|
+
for (f = type->fields; NULL != f; f = f->next) {
|
1052
|
+
text = field_sdl(text, f, with_desc);
|
1053
|
+
}
|
1054
|
+
text = agoo_text_append(text, "}\n", 2);
|
1055
|
+
break;
|
1056
|
+
}
|
1041
1057
|
case GQL_OBJECT:
|
1042
1058
|
case GQL_FRAG: {
|
1043
1059
|
gqlField f;
|
@@ -1126,7 +1142,6 @@ gql_type_sdl(agooText text, gqlType type, bool with_desc) {
|
|
1126
1142
|
text = agoo_text_append(text, " {\n", 3);
|
1127
1143
|
for (a = type->args; NULL != a; a = a->next) {
|
1128
1144
|
text = arg_sdl(text, a, with_desc, false, NULL == a->next);
|
1129
|
-
// TBD zzzzzz
|
1130
1145
|
}
|
1131
1146
|
text = agoo_text_append(text, "}\n", 2);
|
1132
1147
|
break;
|
@@ -1171,12 +1186,6 @@ type_cmp(const void *v0, const void *v1) {
|
|
1171
1186
|
gqlType t1 = *(gqlType*)v1;
|
1172
1187
|
|
1173
1188
|
if (t0->kind == t1->kind) {
|
1174
|
-
if (0 == strcmp("schema", t0->name)) {
|
1175
|
-
return -1;
|
1176
|
-
}
|
1177
|
-
if (0 == strcmp("schema", t1->name)) {
|
1178
|
-
return 1;
|
1179
|
-
}
|
1180
1189
|
return strcmp(t0->name, t1->name);
|
1181
1190
|
}
|
1182
1191
|
return t0->kind - t1->kind;
|
@@ -1268,17 +1277,35 @@ gql_dir_use_arg(agooErr err, gqlDirUse use, const char *key, gqlValue value) {
|
|
1268
1277
|
return AGOO_ERR_OK;
|
1269
1278
|
}
|
1270
1279
|
|
1271
|
-
|
1272
|
-
gql_type_directive_use(gqlType type, gqlDirUse use) {
|
1280
|
+
int
|
1281
|
+
gql_type_directive_use(agooErr err, gqlType type, gqlDirUse use) {
|
1273
1282
|
if (NULL == type->dir) {
|
1274
1283
|
type->dir = use;
|
1284
|
+
} else if (0 == strcmp(use->dir->name, type->dir->dir->name)) {
|
1285
|
+
return agoo_err_set(err, AGOO_ERR_TOO_MANY, "Directive %s on type %s is a duplicate.", use->dir->name, type->name);
|
1275
1286
|
} else {
|
1276
1287
|
gqlDirUse u = type->dir;
|
1277
1288
|
|
1278
1289
|
for (; NULL != u->next; u = u->next) {
|
1290
|
+
if (0 == strcmp(use->dir->name, u->dir->name)) {
|
1291
|
+
return agoo_err_set(err, AGOO_ERR_TOO_MANY, "Directive %s on type %s is a duplicate.", use->dir->name, type->name);
|
1292
|
+
}
|
1279
1293
|
}
|
1280
1294
|
u->next = use;
|
1281
1295
|
}
|
1296
|
+
return AGOO_ERR_OK;
|
1297
|
+
}
|
1298
|
+
|
1299
|
+
bool
|
1300
|
+
gql_type_has_directive_use(gqlType type, const char *dir) {
|
1301
|
+
gqlDirUse u = type->dir;
|
1302
|
+
|
1303
|
+
for (; NULL != u; u = u->next) {
|
1304
|
+
if (0 == strcmp(dir, u->dir->name)) {
|
1305
|
+
return true;
|
1306
|
+
}
|
1307
|
+
}
|
1308
|
+
return false;
|
1282
1309
|
}
|
1283
1310
|
|
1284
1311
|
gqlFrag
|
@@ -1617,7 +1644,9 @@ gql_dump_hook(agooReq req) {
|
|
1617
1644
|
}
|
1618
1645
|
text = gql_schema_sdl(text, with_desc, all);
|
1619
1646
|
cnt = snprintf(buf, sizeof(buf), "HTTP/1.1 200 Okay\r\nContent-Type: application/graphql\r\nContent-Length: %ld\r\n\r\n", text->len);
|
1620
|
-
text = agoo_text_prepend(text, buf, cnt)
|
1647
|
+
if (NULL == (text = agoo_text_prepend(text, buf, cnt))) {
|
1648
|
+
agoo_log_cat(&agoo_error_cat, "Failed to allocate memory for a GraphQL dump.");
|
1649
|
+
}
|
1621
1650
|
agoo_res_set_message(req->res, text);
|
1622
1651
|
}
|
1623
1652
|
|
@@ -1629,6 +1658,7 @@ gql_type_get_field(gqlType type, const char *field) {
|
|
1629
1658
|
return NULL;
|
1630
1659
|
}
|
1631
1660
|
switch (type->kind) {
|
1661
|
+
case GQL_SCHEMA:
|
1632
1662
|
case GQL_OBJECT:
|
1633
1663
|
case GQL_INTERFACE:
|
1634
1664
|
for (f = type->fields; NULL != f; f = f->next) {
|