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.

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
- gql_string_set(agooErr err, gqlValue value, const char *str, int len) {
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
- if (NULL == str) {
838
- value->str.alloced = true;
839
- value->str.ptr = NULL;
840
- } else {
841
- if (0 >= len) {
842
- len = (int)strlen(str);
843
- }
844
- if (len < (int)sizeof(value->str.a)) {
845
- strncpy(value->str.a, str, len);
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, "%d can not be modified.", name);
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
- type_clean(type);
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 ev = (gqlEnumVal)AGOO_MALLOC(sizeof(struct _gqlEnumVal));
681
+ gqlEnumVal last = type->choices;
682
+ gqlEnumVal ev;
683
683
 
684
- if (NULL == ev) {
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
- gqlEnumVal last = type->choices;
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
- void
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) {