agoo 2.5.4 → 2.5.5

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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -0
  3. data/bin/agoo +3 -1
  4. data/ext/agoo/base64.h +3 -3
  5. data/ext/agoo/bind.c +1 -1
  6. data/ext/agoo/bind.h +3 -3
  7. data/ext/agoo/con.c +4 -2
  8. data/ext/agoo/con.h +3 -3
  9. data/ext/agoo/debug.c +7 -0
  10. data/ext/agoo/debug.h +13 -6
  11. data/ext/agoo/doc.c +159 -0
  12. data/ext/agoo/doc.h +34 -0
  13. data/ext/agoo/dtime.h +3 -3
  14. data/ext/agoo/err.h +3 -3
  15. data/ext/agoo/error_stream.h +3 -3
  16. data/ext/agoo/extconf.rb +1 -1
  17. data/ext/agoo/gqlintro.c +333 -0
  18. data/ext/agoo/gqlintro.h +10 -0
  19. data/ext/agoo/gqlvalue.c +1035 -0
  20. data/ext/agoo/gqlvalue.h +88 -0
  21. data/ext/agoo/graphql.c +1078 -0
  22. data/ext/agoo/graphql.h +198 -0
  23. data/ext/agoo/hook.c +2 -0
  24. data/ext/agoo/hook.h +4 -3
  25. data/ext/agoo/http.c +2 -1
  26. data/ext/agoo/http.h +3 -3
  27. data/ext/agoo/kinds.h +3 -3
  28. data/ext/agoo/log.h +3 -3
  29. data/ext/agoo/log_queue.h +3 -3
  30. data/ext/agoo/method.h +3 -3
  31. data/ext/agoo/page.h +3 -3
  32. data/ext/agoo/pub.h +3 -3
  33. data/ext/agoo/queue.h +3 -3
  34. data/ext/agoo/rack_logger.h +3 -3
  35. data/ext/agoo/req.c +2 -2
  36. data/ext/agoo/req.h +3 -3
  37. data/ext/agoo/request.h +3 -3
  38. data/ext/agoo/res.h +3 -3
  39. data/ext/agoo/response.h +3 -3
  40. data/ext/agoo/rhook.c +2 -2
  41. data/ext/agoo/rhook.h +4 -3
  42. data/ext/agoo/rlog.h +3 -3
  43. data/ext/agoo/rresponse.h +3 -3
  44. data/ext/agoo/rserver.c +64 -0
  45. data/ext/agoo/rserver.h +3 -3
  46. data/ext/agoo/rupgraded.c +1 -1
  47. data/ext/agoo/rupgraded.h +3 -3
  48. data/ext/agoo/sdl.c +334 -0
  49. data/ext/agoo/sdl.h +10 -0
  50. data/ext/agoo/seg.h +3 -3
  51. data/ext/agoo/server.c +3 -1
  52. data/ext/agoo/server.h +5 -4
  53. data/ext/agoo/sha1.h +3 -3
  54. data/ext/agoo/sse.h +3 -3
  55. data/ext/agoo/sub.h +3 -3
  56. data/ext/agoo/subject.h +3 -3
  57. data/ext/agoo/text.h +3 -3
  58. data/ext/agoo/upgraded.h +3 -3
  59. data/ext/agoo/websocket.h +3 -3
  60. data/lib/agoo/version.rb +1 -1
  61. data/lib/rack/handler/agoo.rb +3 -1
  62. metadata +12 -12
  63. data/ext/agoo/foo/agoo.c +0 -109
  64. data/ext/agoo/foo/con.c +0 -1220
  65. data/ext/agoo/foo/con.h +0 -65
  66. data/ext/agoo/foo/page.c +0 -699
  67. data/ext/agoo/foo/pub.c +0 -131
  68. data/ext/agoo/foo/pub.h +0 -40
  69. data/ext/agoo/foo/rserver.c +0 -1016
  70. data/ext/agoo/foo/server.c +0 -303
  71. data/ext/agoo/foo/server.h +0 -67
  72. data/ext/agoo/foo/upgraded.c +0 -182
@@ -0,0 +1,10 @@
1
+ // Copyright (c) 2018, Peter Ohler, All rights reserved.
2
+
3
+ #ifndef AGOO_GQLINTRO_H
4
+ #define AGOO_GQLINTRO_H
5
+
6
+ #include "err.h"
7
+
8
+ extern int gql_intro_init(Err err);
9
+
10
+ #endif // AGOO_GQLINTRO_H
@@ -0,0 +1,1035 @@
1
+ // Copyright (c) 2018, Peter Ohler, All rights reserved.
2
+
3
+ #include <stdio.h>
4
+ #include <stdlib.h>
5
+ #include <string.h>
6
+ #include <time.h>
7
+
8
+ #include "debug.h"
9
+ #include "gqlvalue.h"
10
+ #include "graphql.h"
11
+
12
+ static const char spaces[256] = "\n ";
13
+
14
+ // Int type
15
+ static Text
16
+ null_to_text(Text text, gqlValue value, int indent, int depth) {
17
+ return text_append(text, "null", 4);
18
+ }
19
+
20
+ struct _gqlType gql_null_type = {
21
+ .name = "Null",
22
+ .desc = "Null scalar.",
23
+ .kind = GQL_SCALAR,
24
+ .locked = true,
25
+ .core = true,
26
+ .coerce = NULL,
27
+ .destroy = NULL,
28
+ .to_json = null_to_text,
29
+ };
30
+
31
+ // Int type
32
+ static Text
33
+ int_to_text(Text text, gqlValue value, int indent, int depth) {
34
+ char num[32];
35
+ int cnt;
36
+
37
+ cnt = snprintf(num, sizeof(num), "%lld", (long long)value->i);
38
+
39
+ return text_append(text, num, cnt);
40
+ }
41
+
42
+ struct _gqlType gql_int_type = {
43
+ .name = "Int",
44
+ .desc = "Int scalar.",
45
+ .kind = GQL_SCALAR,
46
+ .locked = true,
47
+ .core = true,
48
+ .coerce = NULL,
49
+ .destroy = NULL,
50
+ .to_json = int_to_text,
51
+ };
52
+
53
+ // I64 type, add on type.
54
+ static Text
55
+ i64_to_text(Text text, gqlValue value, int indent, int depth) {
56
+ char num[32];
57
+ int cnt;
58
+
59
+ cnt = snprintf(num, sizeof(num), "%lld", (long long)value->i64);
60
+
61
+ return text_append(text, num, cnt);
62
+ }
63
+
64
+ struct _gqlType gql_i64_type = {
65
+ .name = "I64",
66
+ .desc = "64 bit integer scalar.",
67
+ .kind = GQL_SCALAR,
68
+ .locked = true,
69
+ .core = true,
70
+ .coerce = NULL,
71
+ .destroy = NULL,
72
+ .to_json = i64_to_text,
73
+ };
74
+
75
+ // String type
76
+ static void
77
+ string_destroy(gqlValue value) {
78
+ free((char*)value->str);
79
+ }
80
+
81
+ static Text string_to_text(Text text, gqlValue value, int indent, int depth);
82
+
83
+ struct _gqlType gql_string_type = {
84
+ .name = "String",
85
+ .desc = "String scalar.",
86
+ .kind = GQL_SCALAR,
87
+ .locked = true,
88
+ .core = true,
89
+ .coerce = NULL,
90
+ .destroy = string_destroy,
91
+ .to_json = string_to_text,
92
+ };
93
+
94
+ // Alternative to String but with no destroy needed.
95
+ struct _gqlType gql_str16_type = { // unregistered
96
+ .name = "str16",
97
+ .desc = NULL,
98
+ .kind = GQL_SCALAR,
99
+ .locked = true,
100
+ .core = true,
101
+ .coerce = NULL,
102
+ .destroy = NULL,
103
+ .to_json = string_to_text,
104
+ };
105
+
106
+ static Text
107
+ string_to_text(Text text, gqlValue value, int indent, int depth) {
108
+ if (&gql_str16_type == value->type) {
109
+ text = text_append(text, "\"", 1);
110
+ text = text_append(text, value->str16, -1);
111
+ text = text_append(text, "\"", 1);
112
+ } else if (NULL == value->str) {
113
+ text = text_append(text, "null", 4);
114
+ } else {
115
+ text = text_append(text, "\"", 1);
116
+ text = text_append(text, value->str, -1);
117
+ text = text_append(text, "\"", 1);
118
+ }
119
+ return text;
120
+ }
121
+
122
+ // Bool type
123
+ static Text
124
+ bool_to_text(Text text, gqlValue value, int indent, int depth) {
125
+ if (value->b) {
126
+ text = text_append(text, "true", 4);
127
+ } else {
128
+ text = text_append(text, "false", 5);
129
+ }
130
+ return text;
131
+ }
132
+
133
+ struct _gqlType gql_bool_type = {
134
+ .name = "Boolean",
135
+ .desc = "Boolean scalar.",
136
+ .kind = GQL_SCALAR,
137
+ .locked = true,
138
+ .core = true,
139
+ .coerce = NULL,
140
+ .destroy = NULL,
141
+ .to_json = bool_to_text,
142
+ };
143
+
144
+ // Float type
145
+ static Text
146
+ float_to_text(Text text, gqlValue value, int indent, int depth) {
147
+ char num[32];
148
+ int cnt;
149
+
150
+ cnt = snprintf(num, sizeof(num), "%g", value->f);
151
+
152
+ return text_append(text, num, cnt);
153
+ }
154
+
155
+ struct _gqlType gql_float_type = {
156
+ .name = "Float",
157
+ .desc = "Float scalar.",
158
+ .kind = GQL_SCALAR,
159
+ .locked = true,
160
+ .core = true,
161
+ .coerce = NULL,
162
+ .destroy = NULL,
163
+ .to_json = float_to_text,
164
+ };
165
+
166
+ // Time type
167
+ static const char*
168
+ read_num(const char *s, int len, int *vp) {
169
+ uint32_t v = 0;
170
+
171
+ for (; 0 < len; len--, s++) {
172
+ if ('0' <= *s && *s <= '9') {
173
+ v = v * 10 + *s - '0';
174
+ } else {
175
+ return NULL;
176
+ }
177
+ }
178
+ *vp = (int)v;
179
+
180
+ return s;
181
+ }
182
+
183
+ static const char*
184
+ read_zone(const char *s, int *vp) {
185
+ int hr;
186
+ int min;
187
+
188
+ if (NULL == (s = read_num(s, 2, &hr))) {
189
+ return NULL;
190
+ }
191
+ if (':' != *s) {
192
+ return NULL;
193
+ }
194
+ s++;
195
+ if (NULL == (s = read_num(s, 2, &min))) {
196
+ return NULL;
197
+ }
198
+ *vp = hr * 60 + min;
199
+
200
+ return s;
201
+ }
202
+
203
+ static int64_t
204
+ time_parse(Err err, const char *str, int len) {
205
+ const char *s = str;
206
+ const char *end;
207
+ struct tm tm;
208
+ bool neg = false;
209
+ uint64_t nsecs = 0;
210
+ int i = 9;
211
+ int64_t secs;
212
+
213
+ if (0 > len) {
214
+ len = (int)strlen(str);
215
+ }
216
+ if (len < 10 || 36 < len) {
217
+ err_set(err, ERR_PARSE, "Invalid time format.");
218
+ return 0;
219
+ }
220
+ end = str + len;
221
+ memset(&tm, 0, sizeof(tm));
222
+ if ('-' == *s) {
223
+ s++;
224
+ neg = true;
225
+ }
226
+ if (NULL == (s = read_num(s, 4, &tm.tm_year))) {
227
+ err_set(err, ERR_PARSE, "Invalid time format.");
228
+ return 0;
229
+ }
230
+ if (neg) {
231
+ tm.tm_year = -tm.tm_year;
232
+ neg = false;
233
+ }
234
+ tm.tm_year -= 1900;
235
+ if ('-' != *s) {
236
+ err_set(err, ERR_PARSE, "Invalid time format.");
237
+ return 0;
238
+ }
239
+ s++;
240
+
241
+ if (NULL == (s = read_num(s, 2, &tm.tm_mon))) {
242
+ err_set(err, ERR_PARSE, "Invalid time format.");
243
+ return 0;
244
+ }
245
+ tm.tm_mon--;
246
+ if ('-' != *s) {
247
+ err_set(err, ERR_PARSE, "Invalid time format.");
248
+ return 0;
249
+ }
250
+ s++;
251
+
252
+ if (NULL == (s = read_num(s, 2, &tm.tm_mday))) {
253
+ err_set(err, ERR_PARSE, "Invalid time format.");
254
+ return 0;
255
+ }
256
+
257
+ // If that's the end then pass back the date as a unix time.
258
+ if (end == s) {
259
+ return (int64_t)timegm(&tm) * 1000000000LL;
260
+ }
261
+ switch (*s++) {
262
+ case 'Z':
263
+ if (s == end) {
264
+ return (int64_t)timegm(&tm) * 1000000000LL;
265
+ }
266
+ err_set(err, ERR_PARSE, "Invalid time format.");
267
+ return 0;
268
+ case '-':
269
+ neg = true;
270
+ // fall through
271
+ case '+': {
272
+ int v = 0;
273
+
274
+ if (NULL == (s = read_zone(s, &v))) {
275
+ err_set(err, ERR_PARSE, "Invalid time format.");
276
+ return 0;
277
+ }
278
+ if (neg) {
279
+ v = -v;
280
+ }
281
+ if (s == end) {
282
+ return ((int64_t)timegm(&tm) - (int64_t)v) * 1000000000LL;
283
+ }
284
+ err_set(err, ERR_PARSE, "Invalid time format.");
285
+ return 0;
286
+ }
287
+ case 'T':
288
+ break;
289
+ default:
290
+ err_set(err, ERR_PARSE, "Invalid time format.");
291
+ return 0;
292
+ }
293
+ // T encountered, need space for time and zone
294
+ if (end - s < 9) {
295
+ err_set(err, ERR_PARSE, "Invalid time format.");
296
+ return 0;
297
+ }
298
+ if (NULL == (s = read_num(s, 2, &tm.tm_hour))) {
299
+ return 0;
300
+ }
301
+ if (':' != *s) {
302
+ err_set(err, ERR_PARSE, "Invalid time format.");
303
+ return 0;
304
+ }
305
+ s++;
306
+
307
+ if (NULL == (s = read_num(s, 2, &tm.tm_min))) {
308
+ err_set(err, ERR_PARSE, "Invalid time format.");
309
+ return 0;
310
+ }
311
+ if (':' != *s) {
312
+ err_set(err, ERR_PARSE, "Invalid time format.");
313
+ return 0;
314
+ }
315
+ s++;
316
+
317
+ if (NULL == (s = read_num(s, 2, &tm.tm_sec))) {
318
+ err_set(err, ERR_PARSE, "Invalid time format.");
319
+ return 0;
320
+ }
321
+ switch (*s++) {
322
+ case 'Z':
323
+ if (s == end) {
324
+ return (int64_t)timegm(&tm) * 1000000000LL;
325
+ }
326
+ err_set(err, ERR_PARSE, "Invalid time format.");
327
+ return 0;
328
+ case '-':
329
+ neg = true;
330
+ // fall through
331
+ case '+': {
332
+ int v = 0;
333
+
334
+ if (end - s < 5) {
335
+ err_set(err, ERR_PARSE, "Invalid time format.");
336
+ return 0;
337
+ }
338
+ if (NULL == (s = read_zone(s, &v))) {
339
+ err_set(err, ERR_PARSE, "Invalid time format.");
340
+ return 0;
341
+ }
342
+ if (neg) {
343
+ v = -v;
344
+ }
345
+ if (s == end) {
346
+ return ((int64_t)timegm(&tm) - (int64_t)v) * 1000000000LL;
347
+ }
348
+ err_set(err, ERR_PARSE, "Invalid time format.");
349
+ return 0;
350
+ }
351
+ case '.':
352
+ break;
353
+ default:
354
+ err_set(err, ERR_PARSE, "Invalid time format.");
355
+ return 0;
356
+ }
357
+ for (; 0 < i; i--, s++) {
358
+ if (end <= s) {
359
+ err_set(err, ERR_PARSE, "Invalid time format.");
360
+ return 0;
361
+ }
362
+ if ('0' <= *s && *s <= '9') {
363
+ nsecs = nsecs * 10 + *s - '0';
364
+ } else {
365
+ break;
366
+ }
367
+ }
368
+ for (; 0 < i; i--) {
369
+ nsecs *= 10;
370
+ }
371
+ switch (*s++) {
372
+ case 'Z':
373
+ if (s == end) {
374
+ break;
375
+ }
376
+ err_set(err, ERR_PARSE, "Invalid time format.");
377
+ return 0;
378
+ case '-':
379
+ neg = true;
380
+ // fall through
381
+ case '+': {
382
+ int v = 0;
383
+
384
+ if (end - s < 5) {
385
+ err_set(err, ERR_PARSE, "Invalid time format.");
386
+ return 0;
387
+ }
388
+ if (NULL == (s = read_zone(s, &v))) {
389
+ err_set(err, ERR_PARSE, "Invalid time format.");
390
+ return 0;
391
+ }
392
+ if (neg) {
393
+ v = -v;
394
+ }
395
+ if (s == end) {
396
+ return ((int64_t)timegm(&tm) - (int64_t)v) * 1000000000LL + nsecs;
397
+ }
398
+ err_set(err, ERR_PARSE, "Invalid time format.");
399
+ return 0;
400
+ }
401
+ default:
402
+ if (s != end) {
403
+ err_set(err, ERR_PARSE, "Invalid time format.");
404
+ return 0;
405
+ }
406
+ }
407
+ if (0 <= (secs = (int64_t)timegm(&tm) * 1000000000LL)) {
408
+ return secs + nsecs;
409
+ }
410
+ return secs - nsecs;
411
+ }
412
+
413
+ static Text
414
+ time_to_text(Text text, gqlValue value, int indent, int depth) {
415
+ char str[64];
416
+ int cnt;
417
+ struct tm tm;
418
+ int64_t tt = value->time;
419
+ time_t t = (time_t)(tt / 1000000000LL);
420
+ long nsecs = tt - (int64_t)t * 1000000000LL;
421
+
422
+ if (0 > nsecs) {
423
+ nsecs = -nsecs;
424
+ }
425
+ gmtime_r(&t, &tm);
426
+ cnt = sprintf(str, "\"%04d-%02d-%02dT%02d:%02d:%02d.%09ldZ\"",
427
+ 1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday,
428
+ tm.tm_hour, tm.tm_min, tm.tm_sec, (long)nsecs);
429
+
430
+ return text_append(text, str, cnt);
431
+ }
432
+
433
+ struct _gqlType gql_time_type = {
434
+ .name = "Time",
435
+ .desc = "Time zulu scalar.",
436
+ .kind = GQL_SCALAR,
437
+ .locked = true,
438
+ .core = true,
439
+ .coerce = NULL,
440
+ .destroy = NULL,
441
+ .to_json = time_to_text,
442
+ };
443
+
444
+ // Uuid type
445
+ static int
446
+ hexVal(int c) {
447
+ int h = -1;
448
+
449
+ if ('0' <= c && c <= '9') {
450
+ h = c - '0';
451
+ } else if ('a' <= c && c <= 'f') {
452
+ h = c - 'a' + 10;
453
+ } else if ('A' <= c && c <= 'F') {
454
+ h = c - 'A' + 10;
455
+ }
456
+ return h;
457
+ }
458
+
459
+ // 123e4567-e89b-12d3-a456-426655440000
460
+ static int
461
+ parse_uuid(Err err, const char *str, int len, uint64_t *hip, uint64_t *lop) {
462
+ uint64_t hi = 0;
463
+ uint64_t lo = 0;
464
+ int i;
465
+ int n;
466
+
467
+ if (0 >= len) {
468
+ len = (int)strlen(str);
469
+ }
470
+ if (36 != len || '-' != str[8] || '-' != str[13] || '-' != str[18] || '-' != str[23]) {
471
+ return err_set(err, ERR_PARSE, "not UUID format");
472
+ }
473
+ for (i = 0; i < 8; i++, str++) {
474
+ if (0 > (n = hexVal(*str))) {
475
+ return err_set(err, ERR_PARSE, "not UUID format");
476
+ }
477
+ hi = (hi << 4) + n;
478
+ }
479
+ str++;
480
+ for (i = 0; i < 4; i++, str++) {
481
+ if (0 > (n = hexVal(*str))) {
482
+ return err_set(err, ERR_PARSE, "not UUID format");
483
+ }
484
+ hi = (hi << 4) + n;
485
+ }
486
+ str++;
487
+ for (i = 0; i < 4; i++, str++) {
488
+ if (0 > (n = hexVal(*str))) {
489
+ return err_set(err, ERR_PARSE, "not UUID format");
490
+ }
491
+ hi = (hi << 4) + n;
492
+ }
493
+ str++;
494
+ for (i = 0; i < 4; i++, str++) {
495
+ if (0 > (n = hexVal(*str))) {
496
+ return err_set(err, ERR_PARSE, "not UUID format");
497
+ }
498
+ lo = (lo << 4) + n;
499
+ }
500
+ str++;
501
+ for (i = 0; i < 12; i++, str++) {
502
+ if (0 > (n = hexVal(*str))) {
503
+ return err_set(err, ERR_PARSE, "not UUID format");
504
+ }
505
+ lo = (lo << 4) + n;
506
+ }
507
+ *hip = hi;
508
+ *lop = lo;
509
+
510
+ return ERR_OK;
511
+ }
512
+
513
+ static Text
514
+ uuid_to_text(Text text, gqlValue value, int indent, int depth) {
515
+ char str[64];
516
+ int cnt = sprintf(str, "\"%08lx-%04lx-%04lx-%04lx-%012lx\"",
517
+ (unsigned long)(value->uuid.hi >> 32),
518
+ (unsigned long)((value->uuid.hi >> 16) & 0x000000000000FFFFUL),
519
+ (unsigned long)(value->uuid.hi & 0x000000000000FFFFUL),
520
+ (unsigned long)(value->uuid.lo >> 48),
521
+ (unsigned long)(value->uuid.lo & 0x0000FFFFFFFFFFFFUL));
522
+
523
+ return text_append(text, str, cnt);
524
+ }
525
+
526
+ struct _gqlType gql_uuid_type = {
527
+ .name = "Uuid",
528
+ .desc = "UUID scalar.",
529
+ .kind = GQL_SCALAR,
530
+ .locked = true,
531
+ .core = true,
532
+ .coerce = NULL,
533
+ .destroy = NULL,
534
+ .to_json = uuid_to_text,
535
+ };
536
+
537
+ // Url type
538
+ static void
539
+ url_destroy(gqlValue value) {
540
+ free((char*)value->url);
541
+ }
542
+
543
+ static Text
544
+ url_to_text(Text text, gqlValue value, int indent, int depth) {
545
+ if (NULL == value->url) {
546
+ return text_append(text, "null", 4);
547
+ }
548
+ text = text_append(text, "\"", 1);
549
+ text = text_append(text, value->url, -1);
550
+ text = text_append(text, "\"", 1);
551
+
552
+ return text;
553
+ }
554
+
555
+ struct _gqlType gql_url_type = {
556
+ .name = "Url",
557
+ .desc = "URL scalar.",
558
+ .kind = GQL_SCALAR,
559
+ .locked = true,
560
+ .core = true,
561
+ .coerce = NULL,
562
+ .destroy = url_destroy,
563
+ .to_json = url_to_text,
564
+ };
565
+
566
+ // List, not visible but used for list values.
567
+ static void
568
+ list_destroy(gqlValue value) {
569
+ gqlLink link;
570
+
571
+ while (NULL != (link = value->members)) {
572
+ value->members = link->next;
573
+ gql_value_destroy(link->value);
574
+ DEBUG_ALLOC(mem_graphql_link, link);
575
+ free(link);
576
+ }
577
+ }
578
+
579
+ static Text
580
+ list_to_json(Text text, gqlValue value, int indent, int depth) {
581
+ int i = indent * depth;
582
+ int i2 = i + indent;
583
+ int d2 = depth + 1;
584
+ gqlLink link;
585
+
586
+ if (0 < indent) {
587
+ i++; // for \n
588
+ i2++;
589
+ }
590
+ if ((int)sizeof(spaces) <= i) {
591
+ i2 = sizeof(spaces) - 1;
592
+ i = i2 - indent;
593
+ }
594
+ text = text_append(text, "[", 1);
595
+ for (link = value->members; NULL != link; link = link->next) {
596
+ text = text_append(text, spaces, i2);
597
+ text = link->value->type->to_json(text, link->value, indent, d2);
598
+ if (NULL != link->next) {
599
+ text = text_append(text, ",", 1);
600
+ }
601
+ }
602
+ if (0 < indent) {
603
+ text = text_append(text, spaces, i);
604
+ }
605
+ text = text_append(text, "]", 1);
606
+
607
+ return text;
608
+ }
609
+
610
+ struct _gqlType list_type = { // unregistered
611
+ .name = "__List",
612
+ .desc = NULL,
613
+ .kind = GQL_SCALAR,
614
+ .locked = true,
615
+ .core = true,
616
+ .coerce = NULL,
617
+ .destroy = list_destroy,
618
+ .to_json = list_to_json,
619
+ };
620
+
621
+ // Object, not visible but used for object values.
622
+ static void
623
+ object_destroy(gqlValue value) {
624
+ gqlLink link;
625
+
626
+ while (NULL != (link = value->members)) {
627
+ value->members = link->next;
628
+ gql_value_destroy(link->value);
629
+ free(link->key);
630
+ DEBUG_ALLOC(mem_graphql_link, link);
631
+ free(link);
632
+ }
633
+ }
634
+
635
+ static Text
636
+ object_to_json(Text text, gqlValue value, int indent, int depth) {
637
+ int i = indent * depth;
638
+ int i2 = i + indent;
639
+ int d2 = depth + 1;
640
+ gqlLink link;
641
+
642
+ if (0 < indent) {
643
+ i++; // for \n
644
+ i2++;
645
+ }
646
+ if ((int)sizeof(spaces) <= i) {
647
+ i2 = sizeof(spaces) - 1;
648
+ i = i2 - indent;
649
+ }
650
+ text = text_append(text, "{", 1);
651
+ for (link = value->members; NULL != link; link = link->next) {
652
+ text = text_append(text, spaces, i2);
653
+ text = text_append(text, "\"", 1);
654
+ text = text_append(text, link->key, -1);
655
+ if (0 < indent) {
656
+ text = text_append(text, "\": ", 3);
657
+ } else {
658
+ text = text_append(text, "\":", 2);
659
+ }
660
+ text = link->value->type->to_json(text, link->value, indent, d2);
661
+ if (NULL != link->next) {
662
+ text = text_append(text, ",", 1);
663
+ }
664
+ }
665
+ if (0 < indent) {
666
+ text = text_append(text, spaces, i);
667
+ }
668
+ text = text_append(text, "}", 1);
669
+
670
+ return text;
671
+ }
672
+
673
+ struct _gqlType object_type = { // unregistered
674
+ .name = "__Object",
675
+ .desc = NULL,
676
+ .kind = GQL_SCALAR,
677
+ .locked = true,
678
+ .core = true,
679
+ .coerce = NULL,
680
+ .destroy = object_destroy,
681
+ .to_json = object_to_json,
682
+ };
683
+
684
+ ////////////////////////////////////////////////////////////////////////////////
685
+ void
686
+ gql_value_destroy(gqlValue value) {
687
+ if (NULL != value->type->destroy) {
688
+ value->type->destroy(value);
689
+ }
690
+ DEBUG_ALLOC(mem_graphql_value, value);
691
+ free(value);
692
+ }
693
+
694
+ int
695
+ gql_value_init(Err err) {
696
+ if (ERR_OK != gql_type_set(err, &gql_int_type) ||
697
+ ERR_OK != gql_type_set(err, &gql_i64_type) ||
698
+ ERR_OK != gql_type_set(err, &gql_bool_type) ||
699
+ ERR_OK != gql_type_set(err, &gql_float_type) ||
700
+ ERR_OK != gql_type_set(err, &gql_time_type) ||
701
+ ERR_OK != gql_type_set(err, &gql_uuid_type) ||
702
+ ERR_OK != gql_type_set(err, &gql_url_type) ||
703
+ ERR_OK != gql_type_set(err, &gql_string_type)) {
704
+ return err->code;
705
+ }
706
+ return ERR_OK;
707
+ }
708
+
709
+ /// set functions /////////////////////////////////////////////////////////////
710
+ void
711
+ gql_int_set(gqlValue value, int32_t i) {
712
+ value->type = &gql_int_type;
713
+ value->i = i;
714
+ }
715
+
716
+ void
717
+ gql_i64_set(gqlValue value, int64_t i) {
718
+ value->type = &gql_i64_type;
719
+ value->i64 = i;
720
+ }
721
+
722
+ void
723
+ gql_string_set(gqlValue value, const char *str, int len) {
724
+ value->type = &gql_string_type;
725
+ if (NULL == str) {
726
+ value->str = NULL;
727
+ } else {
728
+ if (0 >= len) {
729
+ len = (int)strlen(str);
730
+ }
731
+ if (len < (int)sizeof(value->str16)) {
732
+ value->type = &gql_str16_type;
733
+ strncpy(value->str16, str, len);
734
+ } else {
735
+ value->str = strndup(str, len);
736
+ }
737
+ }
738
+ }
739
+
740
+ int
741
+ gql_url_set(Err err, gqlValue value, const char *url, int len) {
742
+ value->type = &gql_url_type;
743
+ if (NULL == url) {
744
+ value->url = NULL;
745
+ } else {
746
+ if (0 >= len) {
747
+ len = (int)strlen(url);
748
+ }
749
+ value->url = strndup(url, len);
750
+ }
751
+ return ERR_OK;
752
+ }
753
+
754
+ void
755
+ gql_bool_set(gqlValue value, bool b) {
756
+ value->b = b;
757
+ }
758
+
759
+ void
760
+ gql_float_set(gqlValue value, double f) {
761
+ value->f = f;
762
+ }
763
+
764
+ void
765
+ gql_time_set(gqlValue value, int64_t t) {
766
+ value->time = t;
767
+ }
768
+
769
+ int
770
+ gql_time_str_set(Err err, gqlValue value, const char *str, int len) {
771
+ if (0 >= len) {
772
+ len = (int)strlen(str);
773
+ }
774
+ value->time = time_parse(err, str, len);
775
+
776
+ return err->code;
777
+ }
778
+
779
+ void
780
+ gql_uuid_set(gqlValue value, uint64_t hi, uint64_t lo) {
781
+ value->uuid.hi = hi;
782
+ value->uuid.lo = lo;
783
+ }
784
+
785
+ int
786
+ gql_uuid_str_set(Err err, gqlValue value, const char *str, int len) {
787
+ uint64_t hi = 0;
788
+ uint64_t lo = 0;
789
+
790
+ if (ERR_OK != parse_uuid(err, str, len, &hi, &lo)) {
791
+ return err->code;
792
+ }
793
+ value->uuid.hi = hi;
794
+ value->uuid.lo = lo;
795
+
796
+ return ERR_OK;
797
+ }
798
+
799
+ extern void gql_null_set(gqlValue value);
800
+
801
+ gqlLink
802
+ link_create(Err err, gqlValue item) {
803
+ gqlLink link = (gqlLink)malloc(sizeof(struct _gqlLink));
804
+
805
+ if (NULL == link) {
806
+ err_set(err, ERR_MEMORY, "Failed to allocation memory for a list link.");
807
+ } else {
808
+ DEBUG_ALLOC(mem_graphql_link, link);
809
+ link->next = NULL;
810
+ link->key = NULL;
811
+ link->value = item;
812
+ }
813
+ return link;
814
+ }
815
+
816
+ int
817
+ gql_list_append(Err err, gqlValue list, gqlValue item) {
818
+ gqlLink link = link_create(err, item);
819
+
820
+ if (NULL != link) {
821
+ if (NULL == list->members) {
822
+ list->members = link;
823
+ } else {
824
+ gqlLink last = list->members;
825
+
826
+ for (; NULL != last->next; last = last->next) {
827
+ }
828
+ last->next = link;
829
+ }
830
+ }
831
+ return ERR_OK;
832
+ }
833
+
834
+ int
835
+ gql_list_prepend(Err err, gqlValue list, gqlValue item) {
836
+ gqlLink link = link_create(err, item);
837
+
838
+ if (NULL != link) {
839
+ link->next = list->members;
840
+ list->members = link;
841
+ }
842
+ return ERR_OK;
843
+ }
844
+
845
+ int
846
+ gql_object_set(Err err, gqlValue obj, const char *key, gqlValue item) {
847
+ gqlLink link = link_create(err, item);
848
+
849
+ if (NULL != link) {
850
+ link->key = strdup(key);
851
+ //link->next = obj->members;
852
+ if (NULL == obj->members) {
853
+ obj->members = link;
854
+ } else {
855
+ gqlLink last = obj->members;
856
+
857
+ for (; NULL != last->next; last = last->next) {
858
+ }
859
+ last->next = link;
860
+ }
861
+ }
862
+ return ERR_OK;
863
+ }
864
+
865
+ /// create functions //////////////////////////////////////////////////////////
866
+
867
+ static gqlValue
868
+ value_create(gqlType type) {
869
+ gqlValue v = (gqlValue)malloc(sizeof(struct _gqlValue));
870
+
871
+ if (NULL != v) {
872
+ DEBUG_ALLOC(mem_graphql_value, v);
873
+ memset(v, 0, sizeof(struct _gqlValue));
874
+ v->type = type;
875
+ }
876
+ return v;
877
+ }
878
+
879
+ gqlValue
880
+ gql_int_create(Err err, int32_t i) {
881
+ gqlValue v = value_create(&gql_int_type);
882
+
883
+ if (NULL != v) {
884
+ v->i = i;
885
+ }
886
+ return v;
887
+ }
888
+
889
+ gqlValue
890
+ gql_i64_create(Err err, int64_t i) {
891
+ gqlValue v = value_create(&gql_i64_type);
892
+
893
+ if (NULL != v) {
894
+ v->i64 = i;
895
+ }
896
+ return v;
897
+ }
898
+
899
+ gqlValue
900
+ gql_string_create(Err err, const char *str, int len) {
901
+ gqlValue v;
902
+
903
+ if (0 >= len) {
904
+ len = (int)strlen(str);
905
+ }
906
+ if ((int)sizeof(v->str16) <= len) {
907
+ if (NULL != (v = value_create(&gql_string_type))) {
908
+ v->str = strndup(str, len);
909
+ }
910
+ } else {
911
+ if (NULL != (v = value_create(&gql_str16_type))) {
912
+ strncpy(v->str16, str, len);
913
+ v->str16[len] = '\0';
914
+ }
915
+ }
916
+ return v;
917
+ }
918
+
919
+ gqlValue
920
+ gql_url_create(Err err, const char *url, int len) {
921
+ gqlValue v = value_create(&gql_url_type);
922
+
923
+ if (0 >= len) {
924
+ len = (int)strlen(url);
925
+ }
926
+ if (NULL != v) {
927
+ v->str = strndup(url, len);
928
+ }
929
+ return v;
930
+ }
931
+
932
+ gqlValue
933
+ gql_bool_create(Err err, bool b) {
934
+ gqlValue v = value_create(&gql_bool_type);
935
+
936
+ if (NULL != v) {
937
+ v->b = b;
938
+ }
939
+ return v;
940
+ }
941
+
942
+ gqlValue
943
+ gql_float_create(Err err, double f) {
944
+ gqlValue v = value_create(&gql_float_type);
945
+
946
+ if (NULL != v) {
947
+ v->f = f;
948
+ }
949
+ return v;
950
+ }
951
+
952
+ gqlValue
953
+ gql_time_create(Err err, int64_t t) {
954
+ gqlValue v = value_create(&gql_time_type);
955
+
956
+ if (NULL != v) {
957
+ v->time = t;
958
+ }
959
+ return v;
960
+ }
961
+
962
+ gqlValue
963
+ gql_time_str_create(Err err, const char *str, int len) {
964
+ gqlValue v = value_create(&gql_time_type);
965
+
966
+ if (NULL != v) {
967
+ if (0 >= len) {
968
+ len = (int)strlen(str);
969
+ }
970
+ v->time = time_parse(err, str, len);
971
+ }
972
+ return v;
973
+ }
974
+
975
+ gqlValue
976
+ gql_uuid_create(Err err, uint64_t hi, uint64_t lo) {
977
+ gqlValue v = value_create(&gql_uuid_type);
978
+
979
+ if (NULL != v) {
980
+ v->uuid.hi = hi;
981
+ v->uuid.lo = lo;
982
+ }
983
+ return v;
984
+ }
985
+
986
+ // 123e4567-e89b-12d3-a456-426655440000
987
+ gqlValue
988
+ gql_uuid_str_create(Err err, const char *str, int len) {
989
+ uint64_t hi = 0;
990
+ uint64_t lo = 0;
991
+ gqlValue v;
992
+
993
+ if (ERR_OK != parse_uuid(err, str, len, &hi, &lo)) {
994
+ return NULL;
995
+ }
996
+ if (NULL != (v = value_create(&gql_uuid_type))) {
997
+ v->uuid.hi = hi;
998
+ v->uuid.lo = lo;
999
+ }
1000
+ return v;
1001
+ }
1002
+
1003
+ gqlValue
1004
+ gql_null_create(Err err) {
1005
+ gqlValue v = value_create(&gql_null_type);
1006
+
1007
+ return v;
1008
+ }
1009
+
1010
+ gqlValue
1011
+ gql_list_create(Err err, gqlType itemType) {
1012
+ gqlValue v = value_create(&list_type);
1013
+
1014
+ if (NULL != v) {
1015
+ v->members = NULL;
1016
+ v->member_type = itemType;
1017
+ }
1018
+ return v;
1019
+ }
1020
+
1021
+ gqlValue
1022
+ gql_object_create(Err err) {
1023
+ gqlValue v = value_create(&object_type);
1024
+
1025
+ if (NULL != v) {
1026
+ v->members = NULL;
1027
+ v->member_type = NULL;
1028
+ }
1029
+ return v;
1030
+ }
1031
+
1032
+ Text
1033
+ gql_value_json(Text text, gqlValue value, int indent, int depth) {
1034
+ return value->type->to_json(text, value, indent, depth);
1035
+ }