agoo 2.5.7 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/README.md +38 -0
  4. data/ext/agoo/agoo.c +11 -2
  5. data/ext/agoo/bind.c +15 -20
  6. data/ext/agoo/con.c +32 -25
  7. data/ext/agoo/debug.c +225 -162
  8. data/ext/agoo/debug.h +31 -51
  9. data/ext/agoo/doc.c +278 -5
  10. data/ext/agoo/doc.h +6 -1
  11. data/ext/agoo/err.c +1 -0
  12. data/ext/agoo/err.h +1 -0
  13. data/ext/agoo/error_stream.c +3 -6
  14. data/ext/agoo/gqlcobj.c +12 -0
  15. data/ext/agoo/gqlcobj.h +25 -0
  16. data/ext/agoo/gqleval.c +520 -0
  17. data/ext/agoo/gqleval.h +49 -0
  18. data/ext/agoo/gqlintro.c +1237 -97
  19. data/ext/agoo/gqlintro.h +8 -0
  20. data/ext/agoo/gqljson.c +460 -0
  21. data/ext/agoo/gqljson.h +15 -0
  22. data/ext/agoo/gqlvalue.c +679 -136
  23. data/ext/agoo/gqlvalue.h +29 -7
  24. data/ext/agoo/graphql.c +841 -362
  25. data/ext/agoo/graphql.h +180 -90
  26. data/ext/agoo/hook.c +8 -16
  27. data/ext/agoo/http.c +3 -4
  28. data/ext/agoo/log.c +22 -25
  29. data/ext/agoo/log.h +1 -0
  30. data/ext/agoo/page.c +24 -40
  31. data/ext/agoo/pub.c +23 -21
  32. data/ext/agoo/queue.c +2 -4
  33. data/ext/agoo/ready.c +9 -9
  34. data/ext/agoo/req.c +80 -5
  35. data/ext/agoo/req.h +2 -0
  36. data/ext/agoo/res.c +1 -3
  37. data/ext/agoo/rgraphql.c +753 -0
  38. data/ext/agoo/rresponse.c +9 -15
  39. data/ext/agoo/rserver.c +18 -17
  40. data/ext/agoo/sdl.c +1264 -120
  41. data/ext/agoo/sdl.h +8 -1
  42. data/ext/agoo/sectime.c +136 -0
  43. data/ext/agoo/sectime.h +19 -0
  44. data/ext/agoo/server.c +1 -3
  45. data/ext/agoo/subject.c +2 -4
  46. data/ext/agoo/text.c +124 -18
  47. data/ext/agoo/text.h +5 -1
  48. data/ext/agoo/upgraded.c +2 -4
  49. data/lib/agoo/version.rb +1 -1
  50. data/test/base_handler_test.rb +43 -40
  51. data/test/bind_test.rb +49 -48
  52. data/test/graphql_test.rb +1019 -0
  53. data/test/hijack_test.rb +1 -1
  54. data/test/rack_handler_test.rb +40 -34
  55. data/test/static_test.rb +33 -32
  56. metadata +17 -6
@@ -0,0 +1,15 @@
1
+ // Copyright (c) 2018, Peter Ohler, All rights reserved.
2
+
3
+ #ifndef AGOO_GQLJSON_H
4
+ #define AGOO_GQLJSON_H
5
+
6
+
7
+ #include <stdlib.h>
8
+
9
+ #include "err.h"
10
+
11
+ struct _gqlValue;
12
+
13
+ extern struct _gqlValue* gql_json_parse(agooErr err, const char *json, size_t len);
14
+
15
+ #endif // AGOO_GQLJSON_H
@@ -8,10 +8,11 @@
8
8
  #include "debug.h"
9
9
  #include "gqlvalue.h"
10
10
  #include "graphql.h"
11
+ #include "sectime.h"
11
12
 
12
13
  static const char spaces[256] = "\n ";
13
14
 
14
- // Int type
15
+ // Null type
15
16
  static agooText
16
17
  null_to_text(agooText text, gqlValue value, int indent, int depth) {
17
18
  return agoo_text_append(text, "null", 4);
@@ -21,11 +22,11 @@ struct _gqlType gql_null_type = {
21
22
  .name = "Null",
22
23
  .desc = "Null scalar.",
23
24
  .kind = GQL_SCALAR,
24
- .locked = true,
25
+ .scalar_kind = GQL_SCALAR_NULL,
25
26
  .core = true,
26
- .coerce = NULL,
27
27
  .destroy = NULL,
28
28
  .to_json = null_to_text,
29
+ .to_sdl = null_to_text,
29
30
  };
30
31
 
31
32
  // Int type
@@ -43,11 +44,11 @@ struct _gqlType gql_int_type = {
43
44
  .name = "Int",
44
45
  .desc = "Int scalar.",
45
46
  .kind = GQL_SCALAR,
46
- .locked = true,
47
+ .scalar_kind = GQL_SCALAR_INT,
47
48
  .core = true,
48
- .coerce = NULL,
49
49
  .destroy = NULL,
50
50
  .to_json = int_to_text,
51
+ .to_sdl = int_to_text,
51
52
  };
52
53
 
53
54
  // I64 type, add on type.
@@ -65,60 +66,98 @@ struct _gqlType gql_i64_type = {
65
66
  .name = "I64",
66
67
  .desc = "64 bit integer scalar.",
67
68
  .kind = GQL_SCALAR,
68
- .locked = true,
69
+ .scalar_kind = GQL_SCALAR_I64,
69
70
  .core = true,
70
- .coerce = NULL,
71
71
  .destroy = NULL,
72
72
  .to_json = i64_to_text,
73
+ .to_sdl = i64_to_text,
73
74
  };
74
75
 
75
76
  // String type
76
77
  static void
77
78
  string_destroy(gqlValue value) {
78
- free((char*)value->str);
79
+ if (value->str.alloced) {
80
+ AGOO_FREE((char*)value->str.ptr);
81
+ }
79
82
  }
80
83
 
81
- static agooText string_to_text(agooText text, gqlValue value, int indent, int depth);
84
+ static agooText
85
+ string_to_text(agooText text, gqlValue value, int indent, int depth) {
86
+ if (!value->str.alloced) {
87
+ text = agoo_text_append(text, "\"", 1);
88
+ text = agoo_text_append_json(text, value->str.a, -1);
89
+ text = agoo_text_append(text, "\"", 1);
90
+ } else if (NULL == value->str.ptr) {
91
+ text = agoo_text_append(text, "null", 4);
92
+ } else {
93
+ text = agoo_text_append(text, "\"", 1);
94
+ text = agoo_text_append_json(text, value->str.ptr, -1);
95
+ text = agoo_text_append(text, "\"", 1);
96
+ }
97
+ return text;
98
+ }
82
99
 
83
100
  struct _gqlType gql_string_type = {
84
101
  .name = "String",
85
102
  .desc = "String scalar.",
86
103
  .kind = GQL_SCALAR,
87
- .locked = true,
104
+ .scalar_kind = GQL_SCALAR_STRING,
88
105
  .core = true,
89
- .coerce = NULL,
90
106
  .destroy = string_destroy,
91
107
  .to_json = string_to_text,
108
+ .to_sdl = string_to_text,
92
109
  };
93
110
 
94
- // Alternative to String but with no destroy needed.
95
- struct _gqlType gql_str16_type = { // unregistered
96
- .name = "str16",
97
- .desc = NULL,
111
+ // Token type
112
+ static agooText
113
+ token_to_text(agooText text, gqlValue value, int indent, int depth) {
114
+ if (!value->str.alloced) {
115
+ text = agoo_text_append_json(text, value->str.a, -1);
116
+ } else if (NULL == value->str.ptr) {
117
+ text = agoo_text_append(text, "null", 4);
118
+ } else {
119
+ text = agoo_text_append_json(text, value->str.ptr, -1);
120
+ }
121
+ return text;
122
+ }
123
+
124
+ struct _gqlType gql_token_type = {
125
+ .name = "Token",
126
+ .desc = "Token scalar.",
98
127
  .kind = GQL_SCALAR,
99
- .locked = true,
128
+ .scalar_kind = GQL_SCALAR_TOKEN,
100
129
  .core = true,
101
- .coerce = NULL,
102
- .destroy = NULL,
130
+ .destroy = string_destroy,
103
131
  .to_json = string_to_text,
132
+ .to_sdl = token_to_text,
104
133
  };
105
134
 
135
+ // Variable type ($var)
106
136
  static agooText
107
- string_to_text(agooText text, gqlValue value, int indent, int depth) {
108
- if (&gql_str16_type == value->type) {
109
- text = agoo_text_append(text, "\"", 1);
110
- text = agoo_text_append(text, value->str16, -1);
111
- text = agoo_text_append(text, "\"", 1);
112
- } else if (NULL == value->str) {
137
+ var_to_text(agooText text, gqlValue value, int indent, int depth) {
138
+ if (!value->str.alloced) {
139
+ text = agoo_text_append_char(text, '%');
140
+ text = agoo_text_append_json(text, value->str.a, -1);
141
+ } else if (NULL == value->str.ptr) {
113
142
  text = agoo_text_append(text, "null", 4);
114
143
  } else {
115
- text = agoo_text_append(text, "\"", 1);
116
- text = agoo_text_append(text, value->str, -1);
117
- text = agoo_text_append(text, "\"", 1);
144
+ text = agoo_text_append_char(text, '%');
145
+ text = agoo_text_append_json(text, value->str.ptr, -1);
118
146
  }
119
147
  return text;
120
148
  }
121
149
 
150
+ struct _gqlType gql_var_type = {
151
+ .name = "Var",
152
+ .desc = "Variable scalar.",
153
+ .kind = GQL_SCALAR,
154
+ .scalar_kind = GQL_SCALAR_VAR,
155
+ .core = true,
156
+ .destroy = string_destroy,
157
+ .to_json = var_to_text,
158
+ .to_sdl = var_to_text,
159
+ };
160
+
122
161
  // Bool type
123
162
  static agooText
124
163
  bool_to_text(agooText text, gqlValue value, int indent, int depth) {
@@ -134,11 +173,11 @@ struct _gqlType gql_bool_type = {
134
173
  .name = "Boolean",
135
174
  .desc = "Boolean scalar.",
136
175
  .kind = GQL_SCALAR,
137
- .locked = true,
176
+ .scalar_kind = GQL_SCALAR_BOOL,
138
177
  .core = true,
139
- .coerce = NULL,
140
178
  .destroy = NULL,
141
179
  .to_json = bool_to_text,
180
+ .to_sdl = bool_to_text,
142
181
  };
143
182
 
144
183
  // Float type
@@ -156,11 +195,11 @@ struct _gqlType gql_float_type = {
156
195
  .name = "Float",
157
196
  .desc = "Float scalar.",
158
197
  .kind = GQL_SCALAR,
159
- .locked = true,
198
+ .scalar_kind = GQL_SCALAR_FLOAT,
160
199
  .core = true,
161
- .coerce = NULL,
162
200
  .destroy = NULL,
163
201
  .to_json = float_to_text,
202
+ .to_sdl = float_to_text,
164
203
  };
165
204
 
166
205
  // Time type
@@ -412,20 +451,18 @@ time_parse(agooErr err, const char *str, int len) {
412
451
 
413
452
  static agooText
414
453
  time_to_text(agooText 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;
454
+ char str[64];
455
+ int cnt;
456
+ struct _agooTime at;
457
+ int64_t tt = value->time;
458
+ time_t t = (time_t)(tt / 1000000000LL);
459
+ long nsecs = tt - (int64_t)t * 1000000000LL;
421
460
 
422
461
  if (0 > nsecs) {
423
462
  nsecs = -nsecs;
424
463
  }
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);
464
+ agoo_sectime(t, &at);
465
+ cnt = sprintf(str, "\"%04d-%02d-%02dT%02d:%02d:%02d.%09ldZ\"", at.year, at.mon, at.day, at.hour, at.min, at.sec, (long)nsecs);
429
466
 
430
467
  return agoo_text_append(text, str, cnt);
431
468
  }
@@ -434,11 +471,11 @@ struct _gqlType gql_time_type = {
434
471
  .name = "Time",
435
472
  .desc = "Time zulu scalar.",
436
473
  .kind = GQL_SCALAR,
437
- .locked = true,
474
+ .scalar_kind = GQL_SCALAR_TIME,
438
475
  .core = true,
439
- .coerce = NULL,
440
476
  .destroy = NULL,
441
477
  .to_json = time_to_text,
478
+ .to_sdl = time_to_text,
442
479
  };
443
480
 
444
481
  // Uuid type
@@ -527,40 +564,11 @@ struct _gqlType gql_uuid_type = {
527
564
  .name = "Uuid",
528
565
  .desc = "UUID scalar.",
529
566
  .kind = GQL_SCALAR,
530
- .locked = true,
567
+ .scalar_kind = GQL_SCALAR_UUID,
531
568
  .core = true,
532
- .coerce = NULL,
533
569
  .destroy = NULL,
534
570
  .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 agooText
544
- url_to_text(agooText text, gqlValue value, int indent, int depth) {
545
- if (NULL == value->url) {
546
- return agoo_text_append(text, "null", 4);
547
- }
548
- text = agoo_text_append(text, "\"", 1);
549
- text = agoo_text_append(text, value->url, -1);
550
- text = agoo_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,
571
+ .to_sdl = uuid_to_text,
564
572
  };
565
573
 
566
574
  // List, not visible but used for list values.
@@ -571,8 +579,7 @@ list_destroy(gqlValue value) {
571
579
  while (NULL != (link = value->members)) {
572
580
  value->members = link->next;
573
581
  gql_value_destroy(link->value);
574
- DEBUG_ALLOC(mem_graphql_link, link);
575
- free(link);
582
+ AGOO_FREE(link);
576
583
  }
577
584
  }
578
585
 
@@ -582,7 +589,40 @@ list_to_json(agooText text, gqlValue value, int indent, int depth) {
582
589
  int i2 = i + indent;
583
590
  int d2 = depth + 1;
584
591
  gqlLink link;
585
-
592
+
593
+ if (0 < indent) {
594
+ i++; // for \n
595
+ i2++;
596
+ }
597
+ if ((int)sizeof(spaces) <= i) {
598
+ i2 = sizeof(spaces) - 1;
599
+ i = i2 - indent;
600
+ }
601
+ text = agoo_text_append(text, "[", 1);
602
+ for (link = value->members; NULL != link; link = link->next) {
603
+ if (0 < i2) {
604
+ text = agoo_text_append(text, spaces, i2);
605
+ }
606
+ text = gql_value_json(text, link->value, indent, d2);
607
+ if (NULL != link->next) {
608
+ text = agoo_text_append(text, ",", 1);
609
+ }
610
+ }
611
+ if (0 < indent) {
612
+ text = agoo_text_append(text, spaces, i);
613
+ }
614
+ text = agoo_text_append(text, "]", 1);
615
+
616
+ return text;
617
+ }
618
+
619
+ static agooText
620
+ list_to_sdl(agooText text, gqlValue value, int indent, int depth) {
621
+ int i = indent * depth;
622
+ int i2 = i + indent;
623
+ int d2 = depth + 1;
624
+ gqlLink link;
625
+
586
626
  if (0 < indent) {
587
627
  i++; // for \n
588
628
  i2++;
@@ -593,8 +633,10 @@ list_to_json(agooText text, gqlValue value, int indent, int depth) {
593
633
  }
594
634
  text = agoo_text_append(text, "[", 1);
595
635
  for (link = value->members; NULL != link; link = link->next) {
596
- text = agoo_text_append(text, spaces, i2);
597
- text = link->value->type->to_json(text, link->value, indent, d2);
636
+ if (0 < i2) {
637
+ text = agoo_text_append(text, spaces, i2);
638
+ }
639
+ text = link->value->type->to_sdl(text, link->value, indent, d2);
598
640
  if (NULL != link->next) {
599
641
  text = agoo_text_append(text, ",", 1);
600
642
  }
@@ -611,11 +653,11 @@ struct _gqlType list_type = { // unregistered
611
653
  .name = "__List",
612
654
  .desc = NULL,
613
655
  .kind = GQL_SCALAR,
614
- .locked = true,
656
+ .scalar_kind = GQL_SCALAR_LIST,
615
657
  .core = true,
616
- .coerce = NULL,
617
658
  .destroy = list_destroy,
618
659
  .to_json = list_to_json,
660
+ .to_sdl = list_to_sdl,
619
661
  };
620
662
 
621
663
  // Object, not visible but used for object values.
@@ -626,14 +668,13 @@ object_destroy(gqlValue value) {
626
668
  while (NULL != (link = value->members)) {
627
669
  value->members = link->next;
628
670
  gql_value_destroy(link->value);
629
- free(link->key);
630
- DEBUG_ALLOC(mem_graphql_link, link);
631
- free(link);
671
+ AGOO_FREE(link->key);
672
+ AGOO_FREE(link);
632
673
  }
633
674
  }
634
675
 
635
- static agooText
636
- object_to_json(agooText text, gqlValue value, int indent, int depth) {
676
+ agooText
677
+ gql_object_to_json(agooText text, gqlValue value, int indent, int depth) {
637
678
  int i = indent * depth;
638
679
  int i2 = i + indent;
639
680
  int d2 = depth + 1;
@@ -649,15 +690,56 @@ object_to_json(agooText text, gqlValue value, int indent, int depth) {
649
690
  }
650
691
  text = agoo_text_append(text, "{", 1);
651
692
  for (link = value->members; NULL != link; link = link->next) {
652
- text = agoo_text_append(text, spaces, i2);
693
+ if (0 < i2) {
694
+ text = agoo_text_append(text, spaces, i2);
695
+ }
653
696
  text = agoo_text_append(text, "\"", 1);
654
697
  text = agoo_text_append(text, link->key, -1);
655
698
  if (0 < indent) {
656
- text = agoo_text_append(text, "\": ", 3);
699
+ text = agoo_text_append(text, "\":", 2);
657
700
  } else {
658
701
  text = agoo_text_append(text, "\":", 2);
659
702
  }
660
- text = link->value->type->to_json(text, link->value, indent, d2);
703
+ text = gql_value_json(text, link->value, indent, d2);
704
+ if (NULL != link->next) {
705
+ text = agoo_text_append(text, ",", 1);
706
+ }
707
+ }
708
+ if (0 < indent) {
709
+ text = agoo_text_append(text, spaces, i);
710
+ }
711
+ text = agoo_text_append(text, "}", 1);
712
+
713
+ return text;
714
+ }
715
+
716
+ agooText
717
+ gql_object_to_sdl(agooText text, gqlValue value, int indent, int depth) {
718
+ int i = indent * depth;
719
+ int i2 = i + indent;
720
+ int d2 = depth + 1;
721
+ gqlLink link;
722
+
723
+ if (0 < indent) {
724
+ i++; // for \n
725
+ i2++;
726
+ }
727
+ if ((int)sizeof(spaces) <= i) {
728
+ i2 = sizeof(spaces) - 1;
729
+ i = i2 - indent;
730
+ }
731
+ text = agoo_text_append(text, "{", 1);
732
+ for (link = value->members; NULL != link; link = link->next) {
733
+ if (0 < i2) {
734
+ text = agoo_text_append(text, spaces, i2);
735
+ }
736
+ text = agoo_text_append(text, link->key, -1);
737
+ if (0 < indent) {
738
+ text = agoo_text_append(text, ": ", 2);
739
+ } else {
740
+ text = agoo_text_append(text, ":", 1);
741
+ }
742
+ text = link->value->type->to_sdl(text, link->value, indent, d2);
661
743
  if (NULL != link->next) {
662
744
  text = agoo_text_append(text, ",", 1);
663
745
  }
@@ -674,21 +756,29 @@ struct _gqlType object_type = { // unregistered
674
756
  .name = "__Object",
675
757
  .desc = NULL,
676
758
  .kind = GQL_SCALAR,
677
- .locked = true,
759
+ .scalar_kind = GQL_SCALAR_OBJECT,
678
760
  .core = true,
679
- .coerce = NULL,
680
761
  .destroy = object_destroy,
681
- .to_json = object_to_json,
762
+ .to_json = gql_object_to_json,
763
+ .to_sdl = gql_object_to_sdl,
682
764
  };
683
765
 
684
766
  ////////////////////////////////////////////////////////////////////////////////
685
767
  void
686
768
  gql_value_destroy(gqlValue value) {
687
- if (NULL != value->type->destroy) {
688
- value->type->destroy(value);
769
+ if (NULL != value) {
770
+ if (GQL_SCALAR == value->type->kind) {
771
+ if (NULL != value->type->destroy) {
772
+ value->type->destroy(value);
773
+ }
774
+ } else if (GQL_ENUM == value->type->kind) {
775
+ // TBD destroy string
776
+ string_destroy(value);
777
+ } else {
778
+ return;
779
+ }
780
+ AGOO_FREE(value);
689
781
  }
690
- DEBUG_ALLOC(mem_graphql_value, value);
691
- free(value);
692
782
  }
693
783
 
694
784
  int
@@ -699,7 +789,6 @@ gql_value_init(agooErr err) {
699
789
  AGOO_ERR_OK != gql_type_set(err, &gql_float_type) ||
700
790
  AGOO_ERR_OK != gql_type_set(err, &gql_time_type) ||
701
791
  AGOO_ERR_OK != gql_type_set(err, &gql_uuid_type) ||
702
- AGOO_ERR_OK != gql_type_set(err, &gql_url_type) ||
703
792
  AGOO_ERR_OK != gql_type_set(err, &gql_string_type)) {
704
793
  return err->code;
705
794
  }
@@ -723,16 +812,18 @@ int
723
812
  gql_string_set(agooErr err, gqlValue value, const char *str, int len) {
724
813
  value->type = &gql_string_type;
725
814
  if (NULL == str) {
726
- value->str = NULL;
815
+ value->str.alloced = true;
816
+ value->str.ptr = NULL;
727
817
  } else {
728
818
  if (0 >= len) {
729
819
  len = (int)strlen(str);
730
820
  }
731
- if (len < (int)sizeof(value->str16)) {
732
- value->type = &gql_str16_type;
733
- strncpy(value->str16, str, len);
821
+ if (len < (int)sizeof(value->str.a)) {
822
+ strncpy(value->str.a, str, len);
823
+ value->str.alloced = false;
734
824
  } else {
735
- if (NULL == (value->str = strndup(str, len))) {
825
+ value->str.alloced = true;
826
+ if (NULL == (value->str.ptr = AGOO_STRNDUP(str, len))) {
736
827
  return agoo_err_set(err, AGOO_ERR_MEMORY, "strndup of length %d failed.", len);
737
828
  }
738
829
  }
@@ -741,16 +832,23 @@ gql_string_set(agooErr err, gqlValue value, const char *str, int len) {
741
832
  }
742
833
 
743
834
  int
744
- gql_url_set(agooErr err, gqlValue value, const char *url, int len) {
745
- value->type = &gql_url_type;
746
- if (NULL == url) {
747
- value->url = NULL;
835
+ gql_token_set(agooErr err, gqlValue value, const char *str, int len) {
836
+ value->type = &gql_token_type;
837
+ if (NULL == str) {
838
+ value->str.alloced = true;
839
+ value->str.ptr = NULL;
748
840
  } else {
749
841
  if (0 >= len) {
750
- len = (int)strlen(url);
842
+ len = (int)strlen(str);
751
843
  }
752
- if (NULL == (value->url = strndup(url, len))) {
753
- return agoo_err_set(err, AGOO_ERR_MEMORY, "strndup of length %d failed.", len);
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_set(err, AGOO_ERR_MEMORY, "strndup of length %d failed.", len);
851
+ }
754
852
  }
755
853
  }
756
854
  return AGOO_ERR_OK;
@@ -758,21 +856,25 @@ gql_url_set(agooErr err, gqlValue value, const char *url, int len) {
758
856
 
759
857
  void
760
858
  gql_bool_set(gqlValue value, bool b) {
859
+ value->type = &gql_bool_type;
761
860
  value->b = b;
762
861
  }
763
862
 
764
863
  void
765
864
  gql_float_set(gqlValue value, double f) {
865
+ value->type = &gql_float_type;
766
866
  value->f = f;
767
867
  }
768
868
 
769
869
  void
770
870
  gql_time_set(gqlValue value, int64_t t) {
871
+ value->type = &gql_time_type;
771
872
  value->time = t;
772
873
  }
773
874
 
774
875
  int
775
876
  gql_time_str_set(agooErr err, gqlValue value, const char *str, int len) {
877
+ value->type = &gql_time_type;
776
878
  if (0 >= len) {
777
879
  len = (int)strlen(str);
778
880
  }
@@ -783,6 +885,7 @@ gql_time_str_set(agooErr err, gqlValue value, const char *str, int len) {
783
885
 
784
886
  void
785
887
  gql_uuid_set(gqlValue value, uint64_t hi, uint64_t lo) {
888
+ value->type = &gql_uuid_type;
786
889
  value->uuid.hi = hi;
787
890
  value->uuid.lo = lo;
788
891
  }
@@ -795,6 +898,7 @@ gql_uuid_str_set(agooErr err, gqlValue value, const char *str, int len) {
795
898
  if (AGOO_ERR_OK != parse_uuid(err, str, len, &hi, &lo)) {
796
899
  return err->code;
797
900
  }
901
+ value->type = &gql_uuid_type;
798
902
  value->uuid.hi = hi;
799
903
  value->uuid.lo = lo;
800
904
 
@@ -804,23 +908,37 @@ gql_uuid_str_set(agooErr err, gqlValue value, const char *str, int len) {
804
908
  extern void gql_null_set(gqlValue value);
805
909
 
806
910
  gqlLink
807
- link_create(agooErr err, gqlValue item) {
808
- gqlLink link = (gqlLink)malloc(sizeof(struct _gqlLink));
911
+ gql_link_create(agooErr err, const char *key, gqlValue item) {
912
+ gqlLink link = (gqlLink)AGOO_MALLOC(sizeof(struct _gqlLink));
809
913
 
810
914
  if (NULL == link) {
811
915
  agoo_err_set(err, AGOO_ERR_MEMORY, "Failed to allocation memory for a list link.");
812
916
  } else {
813
- DEBUG_ALLOC(mem_graphql_link, link);
814
917
  link->next = NULL;
815
918
  link->key = NULL;
919
+ if (NULL != key) {
920
+ if (NULL == (link->key = AGOO_STRDUP(key))) {
921
+ agoo_err_set(err, AGOO_ERR_MEMORY, "strdup() failed.");
922
+ return NULL;
923
+ }
924
+ }
816
925
  link->value = item;
817
926
  }
818
927
  return link;
819
928
  }
820
929
 
930
+ void
931
+ gql_link_destroy(gqlLink link) {
932
+ AGOO_FREE(link->key);
933
+ if (NULL != link->value) {
934
+ gql_value_destroy(link->value);
935
+ }
936
+ AGOO_FREE(link);
937
+ }
938
+
821
939
  int
822
940
  gql_list_append(agooErr err, gqlValue list, gqlValue item) {
823
- gqlLink link = link_create(err, item);
941
+ gqlLink link = gql_link_create(err, NULL, item);
824
942
 
825
943
  if (NULL != link) {
826
944
  if (NULL == list->members) {
@@ -838,7 +956,7 @@ gql_list_append(agooErr err, gqlValue list, gqlValue item) {
838
956
 
839
957
  int
840
958
  gql_list_prepend(agooErr err, gqlValue list, gqlValue item) {
841
- gqlLink link = link_create(err, item);
959
+ gqlLink link = gql_link_create(err, NULL, item);
842
960
 
843
961
  if (NULL != link) {
844
962
  link->next = list->members;
@@ -849,10 +967,9 @@ gql_list_prepend(agooErr err, gqlValue list, gqlValue item) {
849
967
 
850
968
  int
851
969
  gql_object_set(agooErr err, gqlValue obj, const char *key, gqlValue item) {
852
- gqlLink link = link_create(err, item);
970
+ gqlLink link = gql_link_create(err, key, item);
853
971
 
854
972
  if (NULL != link) {
855
- link->key = strdup(key);
856
973
  //link->next = obj->members;
857
974
  if (NULL == obj->members) {
858
975
  obj->members = link;
@@ -871,10 +988,9 @@ gql_object_set(agooErr err, gqlValue obj, const char *key, gqlValue item) {
871
988
 
872
989
  static gqlValue
873
990
  value_create(gqlType type) {
874
- gqlValue v = (gqlValue)malloc(sizeof(struct _gqlValue));
991
+ gqlValue v = (gqlValue)AGOO_MALLOC(sizeof(struct _gqlValue));
875
992
 
876
993
  if (NULL != v) {
877
- DEBUG_ALLOC(mem_graphql_value, v);
878
994
  memset(v, 0, sizeof(struct _gqlValue));
879
995
  v->type = type;
880
996
  }
@@ -908,35 +1024,67 @@ gql_string_create(agooErr err, const char *str, int len) {
908
1024
  if (0 >= len) {
909
1025
  len = (int)strlen(str);
910
1026
  }
911
- if ((int)sizeof(v->str16) <= len) {
912
- if (NULL != (v = value_create(&gql_string_type))) {
913
- if (NULL == (v->str = strndup(str, len))) {
1027
+ if (NULL != (v = value_create(&gql_string_type))) {
1028
+ if ((int)sizeof(v->str.a) <= len) {
1029
+ v->str.alloced = true;
1030
+ if (NULL == (v->str.ptr = AGOO_STRNDUP(str, len))) {
914
1031
  agoo_err_set(err, AGOO_ERR_MEMORY, "strndup of length %d failed.", len);
915
1032
  return NULL;
916
1033
  }
1034
+ } else {
1035
+ v->str.alloced = false;
1036
+ strncpy(v->str.a, str, len);
1037
+ v->str.a[len] = '\0';
917
1038
  }
918
- } else {
919
- if (NULL != (v = value_create(&gql_str16_type))) {
920
- strncpy(v->str16, str, len);
921
- v->str16[len] = '\0';
1039
+ }
1040
+ return v;
1041
+ }
1042
+
1043
+ gqlValue
1044
+ gql_token_create(agooErr err, const char *str, int len, gqlType type) {
1045
+ gqlValue v;
1046
+
1047
+ if (0 >= len) {
1048
+ len = (int)strlen(str);
1049
+ }
1050
+ if (NULL == type || GQL_ENUM != type->kind) {
1051
+ type = &gql_token_type;
1052
+ }
1053
+ if (NULL != (v = value_create(type))) {
1054
+ if ((int)sizeof(v->str.a) <= len) {
1055
+ v->str.alloced = true;
1056
+ if (NULL == (v->str.ptr = AGOO_STRNDUP(str, len))) {
1057
+ agoo_err_set(err, AGOO_ERR_MEMORY, "strndup of length %d failed.", len);
1058
+ return NULL;
1059
+ }
1060
+ } else {
1061
+ v->str.alloced = false;
1062
+ strncpy(v->str.a, str, len);
1063
+ v->str.a[len] = '\0';
922
1064
  }
923
1065
  }
924
1066
  return v;
925
1067
  }
926
1068
 
927
1069
  gqlValue
928
- gql_url_create(agooErr err, const char *url, int len) {
929
- gqlValue v = value_create(&gql_url_type);
1070
+ gql_var_create(agooErr err, const char *str, int len) {
1071
+ gqlValue v;
930
1072
 
931
1073
  if (0 >= len) {
932
- len = (int)strlen(url);
1074
+ len = (int)strlen(str);
933
1075
  }
934
- if (NULL != v) {
935
- if (NULL == (v->str = strndup(url, len))) {
936
- agoo_err_set(err, AGOO_ERR_MEMORY, "strndup of length %d failed.", len);
937
- return NULL;
1076
+ if (NULL != (v = value_create(&gql_var_type))) {
1077
+ if ((int)sizeof(v->str.a) <= len) {
1078
+ v->str.alloced = true;
1079
+ if (NULL == (v->str.ptr = AGOO_STRNDUP(str, len))) {
1080
+ agoo_err_set(err, AGOO_ERR_MEMORY, "strndup of length %d failed.", len);
1081
+ return NULL;
1082
+ }
1083
+ } else {
1084
+ v->str.alloced = false;
1085
+ strncpy(v->str.a, str, len);
1086
+ v->str.a[len] = '\0';
938
1087
  }
939
-
940
1088
  }
941
1089
  return v;
942
1090
  }
@@ -1020,12 +1168,12 @@ gql_null_create(agooErr err) {
1020
1168
  }
1021
1169
 
1022
1170
  gqlValue
1023
- gql_list_create(agooErr err, gqlType itemType) {
1171
+ gql_list_create(agooErr err, gqlType item_type) {
1024
1172
  gqlValue v = value_create(&list_type);
1025
1173
 
1026
1174
  if (NULL != v) {
1027
1175
  v->members = NULL;
1028
- v->member_type = itemType;
1176
+ v->member_type = item_type;
1029
1177
  }
1030
1178
  return v;
1031
1179
  }
@@ -1043,5 +1191,400 @@ gql_object_create(agooErr err) {
1043
1191
 
1044
1192
  agooText
1045
1193
  gql_value_json(agooText text, gqlValue value, int indent, int depth) {
1046
- return value->type->to_json(text, value, indent, depth);
1194
+ if (NULL == value->type || GQL_SCALAR != value->type->kind) {
1195
+ if (GQL_ENUM == value->type->kind) {
1196
+ text = string_to_text(text, value, indent, depth);
1197
+ } else {
1198
+ text = agoo_text_append(text, "null", 4);
1199
+ }
1200
+ } else if (NULL == value->type->to_json) {
1201
+ text = agoo_text_append(text, "null", 4);
1202
+ } else {
1203
+ text = value->type->to_json(text, value, indent, depth);
1204
+ }
1205
+ return text;
1206
+ }
1207
+
1208
+ agooText
1209
+ gql_value_sdl(agooText text, gqlValue value, int indent, int depth) {
1210
+ if (NULL == value->type || GQL_SCALAR != value->type->kind) {
1211
+ if (GQL_ENUM == value->type->kind) {
1212
+ text = token_to_text(text, value, indent, depth);
1213
+ } else {
1214
+ text = agoo_text_append(text, "null", 4);
1215
+ }
1216
+ } else if (NULL == value->type->to_sdl) {
1217
+ text = agoo_text_append(text, "null", 4);
1218
+ } else {
1219
+ text = value->type->to_sdl(text, value, indent, depth);
1220
+ }
1221
+ return text;
1222
+ }
1223
+
1224
+ const char*
1225
+ gql_string_get(gqlValue value) {
1226
+ const char *s = NULL;
1227
+
1228
+ if (NULL != value) {
1229
+ if (&gql_string_type == value->type || &gql_token_type == value->type || &gql_var_type == value->type ||
1230
+ GQL_ENUM == value->type->kind) {
1231
+ if (value->str.alloced) {
1232
+ s = value->str.ptr;
1233
+ } else {
1234
+ s = value->str.a;
1235
+ }
1236
+ }
1237
+ }
1238
+ return s;
1239
+ }
1240
+
1241
+ static int
1242
+ convert_to_bool(agooErr err, gqlValue value) {
1243
+ switch (value->type->scalar_kind) {
1244
+ case GQL_SCALAR_INT:
1245
+ gql_bool_set(value, 0 != value->i);
1246
+ break;
1247
+ case GQL_SCALAR_I64:
1248
+ gql_bool_set(value, 0 != value->i64);
1249
+ break;
1250
+ case GQL_SCALAR_FLOAT:
1251
+ gql_bool_set(value, 0.0 != value->f);
1252
+ break;
1253
+ case GQL_SCALAR_STRING:
1254
+ case GQL_SCALAR_TOKEN: {
1255
+ const char *s = gql_string_get(value);
1256
+
1257
+ value->type = &gql_bool_type;
1258
+ if (0 == strcasecmp("true", s)) {
1259
+ value->b = true;
1260
+ } else if (0 == strcasecmp("false", s)) {
1261
+ value->b = false;
1262
+ } else {
1263
+ agoo_err_set(err, AGOO_ERR_PARSE, "Can not coerce a String of '%s' into a Boolean value.", s);
1264
+ }
1265
+ if (value->str.alloced) {
1266
+ AGOO_FREE((char*)value->str.ptr);
1267
+ }
1268
+ break;
1269
+ }
1270
+ default:
1271
+ agoo_err_set(err, AGOO_ERR_PARSE, "Can not coerce a %s into a Boolean value.", value->type->name);
1272
+ break;
1273
+ }
1274
+ return err->code;
1275
+ }
1276
+
1277
+ static int
1278
+ convert_to_int(agooErr err, gqlValue value) {
1279
+ switch (value->type->scalar_kind) {
1280
+ case GQL_SCALAR_I64:
1281
+ if (value->i64 < INT32_MIN || INT32_MAX < value->i64) {
1282
+ agoo_err_set(err, ERANGE, "Can not coerce a %lld into an Int value. Out of range.", (long long)value->i64);
1283
+ } else {
1284
+ gql_int_set(value, (int32_t)value->i64);
1285
+ }
1286
+ break;
1287
+ case GQL_SCALAR_FLOAT:
1288
+ if (value->f < (double)INT32_MIN || (double)INT32_MAX < value->f) {
1289
+ agoo_err_set(err, ERANGE, "Can not coerce a %g into an Int value. Out of range.", value->f);
1290
+ } else if ((double)(int32_t)value->f != value->f) {
1291
+ agoo_err_set(err, ERANGE, "Can not coerce a %g into an Int value. Loss of precision.", value->f);
1292
+ } else {
1293
+ gql_int_set(value, (int32_t)value->f);
1294
+ }
1295
+ break;
1296
+ case GQL_SCALAR_STRING: {
1297
+ const char *s = gql_string_get(value);
1298
+ char *end;
1299
+ long i = strtol(s, &end, 10);
1300
+
1301
+ if ('\0' != *end || (0 == i && 0 != errno)) {
1302
+ agoo_err_set(err, ERANGE, "Can not coerce a '%s' into an Int value.", s);
1303
+ } else if (i < INT32_MIN || INT32_MAX < i) {
1304
+ agoo_err_set(err, ERANGE, "Can not coerce a %lld into an Int value. Out of range.", (long long)i);
1305
+ } else {
1306
+ gql_int_set(value, (int32_t)i);
1307
+ if (value->str.alloced) {
1308
+ AGOO_FREE((char*)value->str.ptr);
1309
+ }
1310
+ }
1311
+ break;
1312
+ }
1313
+ default:
1314
+ agoo_err_set(err, AGOO_ERR_PARSE, "Can not coerce a %s into an Int value.", value->type->name);
1315
+ break;
1316
+ }
1317
+ return err->code;
1318
+ }
1319
+
1320
+ static int
1321
+ convert_to_i64(agooErr err, gqlValue value) {
1322
+ switch (value->type->scalar_kind) {
1323
+ case GQL_SCALAR_INT:
1324
+ gql_i64_set(value, (int64_t)value->i);
1325
+ break;
1326
+ case GQL_SCALAR_FLOAT:
1327
+ if ((double)(int64_t)value->f != value->f) {
1328
+ agoo_err_set(err, ERANGE, "Can not coerce a %g into an I64 value. Loss of precision.", value->f);
1329
+ } else {
1330
+ gql_i64_set(value, (int64_t)value->f);
1331
+ }
1332
+ break;
1333
+ case GQL_SCALAR_STRING: {
1334
+ const char *s = gql_string_get(value);
1335
+ char *end;
1336
+ long long i = strtoll(s, &end, 10);
1337
+
1338
+ if ('\0' != *end || (0 == i && 0 != errno)) {
1339
+ agoo_err_set(err, ERANGE, "Can not coerce a '%s' into an I64 value.", s);
1340
+ } else {
1341
+ gql_i64_set(value, (int64_t)i);
1342
+ if (value->str.alloced) {
1343
+ AGOO_FREE((char*)value->str.ptr);
1344
+ }
1345
+ }
1346
+ break;
1347
+ }
1348
+ case GQL_SCALAR_TIME:
1349
+ gql_i64_set(value, (int64_t)value->time);
1350
+ break;
1351
+ default:
1352
+ agoo_err_set(err, AGOO_ERR_PARSE, "Can not coerce a %s into an I64 value.", value->type->name);
1353
+ break;
1354
+ }
1355
+ return err->code;
1356
+ }
1357
+
1358
+ static int
1359
+ convert_to_float(agooErr err, gqlValue value) {
1360
+ switch (value->type->scalar_kind) {
1361
+ case GQL_SCALAR_INT:
1362
+ gql_float_set(value, (double)value->i);
1363
+ break;
1364
+ case GQL_SCALAR_I64:
1365
+ gql_float_set(value, (double)value->i64);
1366
+ break;
1367
+ case GQL_SCALAR_STRING: {
1368
+ const char *s = gql_string_get(value);
1369
+ char *end;
1370
+ double d = strtod(s, &end);
1371
+
1372
+ if ('\0' != *end) {
1373
+ agoo_err_set(err, ERANGE, "Can not coerce a '%s' into a Float value.", s);
1374
+ } else {
1375
+ gql_float_set(value, d);
1376
+ if (value->str.alloced) {
1377
+ AGOO_FREE((char*)value->str.ptr);
1378
+ }
1379
+ }
1380
+ break;
1381
+ }
1382
+ case GQL_SCALAR_TIME:
1383
+ gql_float_set(value, (double)value->time / 1000000000.0);
1384
+ break;
1385
+ default:
1386
+ agoo_err_set(err, AGOO_ERR_PARSE, "Can not coerce a %s into a Float value.", value->type->name);
1387
+ break;
1388
+ }
1389
+ return err->code;
1390
+ }
1391
+
1392
+ static int
1393
+ convert_to_string(agooErr err, gqlValue value) {
1394
+ char buf[64];
1395
+ int cnt;
1396
+
1397
+ switch (value->type->scalar_kind) {
1398
+ case GQL_SCALAR_BOOL:
1399
+ if (value->b) {
1400
+ gql_string_set(err, value, "true", 4);
1401
+ } else {
1402
+ gql_string_set(err, value, "false", 5);
1403
+ }
1404
+ break;
1405
+ case GQL_SCALAR_INT:
1406
+ cnt = sprintf(buf, "%d", value->i);
1407
+ gql_string_set(err, value, buf, cnt);
1408
+ break;
1409
+ case GQL_SCALAR_I64:
1410
+ cnt = sprintf(buf, "%lld", (long long)value->i64);
1411
+ gql_string_set(err, value, buf, cnt);
1412
+ break;
1413
+ case GQL_SCALAR_FLOAT:
1414
+ cnt = sprintf(buf, "%g", value->f);
1415
+ gql_string_set(err, value, buf, cnt);
1416
+ break;
1417
+ case GQL_SCALAR_TOKEN:
1418
+ value->type = &gql_string_type;
1419
+ break;
1420
+ case GQL_SCALAR_TIME: {
1421
+ struct _agooTime at;
1422
+ int64_t tt = value->time;
1423
+ time_t t = (time_t)(tt / 1000000000LL);
1424
+ long nsecs = tt - (int64_t)t * 1000000000LL;
1425
+
1426
+ if (0 > nsecs) {
1427
+ nsecs = -nsecs;
1428
+ }
1429
+ agoo_sectime(t, &at);
1430
+ cnt = sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d.%09ldZ", at.year, at.mon, at.day, at.hour, at.min, at.sec, (long)nsecs);
1431
+ gql_string_set(err, value, buf, cnt);
1432
+ break;
1433
+ }
1434
+ case GQL_SCALAR_UUID:
1435
+ cnt = sprintf(buf, "%08lx-%04lx-%04lx-%04lx-%012lx",
1436
+ (unsigned long)(value->uuid.hi >> 32),
1437
+ (unsigned long)((value->uuid.hi >> 16) & 0x000000000000FFFFUL),
1438
+ (unsigned long)(value->uuid.hi & 0x000000000000FFFFUL),
1439
+ (unsigned long)(value->uuid.lo >> 48),
1440
+ (unsigned long)(value->uuid.lo & 0x0000FFFFFFFFFFFFUL));
1441
+ gql_string_set(err, value, buf, cnt);
1442
+ break;
1443
+ default:
1444
+ agoo_err_set(err, AGOO_ERR_PARSE, "Can not coerce a %s into a String value.", value->type->name);
1445
+ break;
1446
+ }
1447
+ return err->code;
1448
+ }
1449
+
1450
+ static int
1451
+ convert_to_token(agooErr err, gqlValue value) {
1452
+ switch (value->type->scalar_kind) {
1453
+ case GQL_SCALAR_STRING:
1454
+ value->type = &gql_token_type;
1455
+ break;
1456
+ default:
1457
+ agoo_err_set(err, AGOO_ERR_PARSE, "Can not coerce a %s into a token value.", value->type->name);
1458
+ break;
1459
+ }
1460
+ return err->code;
1461
+ }
1462
+
1463
+ static int
1464
+ convert_to_time(agooErr err, gqlValue value) {
1465
+ switch (value->type->scalar_kind) {
1466
+ case GQL_SCALAR_I64:
1467
+ gql_time_set(value, value->i64);
1468
+ break;
1469
+ case GQL_SCALAR_STRING: {
1470
+ int64_t nsecs = time_parse(err, gql_string_get(value), -1);
1471
+
1472
+ if (AGOO_ERR_OK == err->code) {
1473
+ if (value->str.alloced) {
1474
+ AGOO_FREE((char*)value->str.ptr);
1475
+ }
1476
+ gql_time_set(value, nsecs);
1477
+ }
1478
+ break;
1479
+ }
1480
+ default:
1481
+ agoo_err_set(err, AGOO_ERR_PARSE, "Can not coerce a %s into a Time value.", value->type->name);
1482
+ break;
1483
+ }
1484
+ return err->code;
1485
+ }
1486
+
1487
+ static int
1488
+ convert_to_uuid(agooErr err, gqlValue value) {
1489
+ switch (value->type->scalar_kind) {
1490
+ case GQL_SCALAR_STRING: {
1491
+ const char *s = gql_string_get(value);
1492
+ bool alloced = value->str.alloced;
1493
+
1494
+ if (AGOO_ERR_OK == gql_uuid_str_set(err, value, s, 0)) {
1495
+ if (alloced) {
1496
+ AGOO_FREE((char*)s);
1497
+ }
1498
+ }
1499
+ break;
1500
+ }
1501
+ default:
1502
+ agoo_err_set(err, AGOO_ERR_PARSE, "Can not coerce a %s into a UUID value.", value->type->name);
1503
+ break;
1504
+ }
1505
+ return err->code;
1506
+ }
1507
+
1508
+ int
1509
+ gql_value_convert(agooErr err, gqlValue value, struct _gqlType *type) {
1510
+ int code = AGOO_ERR_OK;
1511
+
1512
+ if (type != value->type) {
1513
+ switch (type->scalar_kind) {
1514
+ case GQL_SCALAR_BOOL:
1515
+ code = convert_to_bool(err, value);
1516
+ break;
1517
+ case GQL_SCALAR_INT:
1518
+ code = convert_to_int(err, value);
1519
+ break;
1520
+ case GQL_SCALAR_I64:
1521
+ code = convert_to_i64(err, value);
1522
+ break;
1523
+ case GQL_SCALAR_FLOAT:
1524
+ code = convert_to_float(err, value);
1525
+ break;
1526
+ case GQL_SCALAR_STRING:
1527
+ code = convert_to_string(err, value);
1528
+ break;
1529
+ case GQL_SCALAR_TOKEN:
1530
+ code = convert_to_token(err, value);
1531
+ break;
1532
+ case GQL_SCALAR_TIME:
1533
+ code = convert_to_time(err, value);
1534
+ break;
1535
+ case GQL_SCALAR_UUID:
1536
+ code = convert_to_uuid(err, value);
1537
+ break;
1538
+ default:
1539
+ break;
1540
+ }
1541
+ }
1542
+ return code;
1047
1543
  }
1544
+
1545
+ gqlValue
1546
+ gql_value_dup(agooErr err, gqlValue value) {
1547
+ gqlValue dup = value_create(value->type);
1548
+
1549
+ if (NULL == dup) {
1550
+ agoo_err_set(err, AGOO_ERR_MEMORY, "failed to duplicate a value.");
1551
+ return NULL;
1552
+ }
1553
+ switch (value->type->scalar_kind) {
1554
+ case GQL_SCALAR_BOOL:
1555
+ dup->b = value->b;
1556
+ break;
1557
+ case GQL_SCALAR_INT:
1558
+ dup->i = value->i;
1559
+ break;
1560
+ case GQL_SCALAR_I64:
1561
+ dup->i64 = value->i64;
1562
+ break;
1563
+ case GQL_SCALAR_FLOAT:
1564
+ dup->f = value->f;
1565
+ break;
1566
+ case GQL_SCALAR_STRING:
1567
+ case GQL_SCALAR_TOKEN:
1568
+ if (value->str.alloced) {
1569
+ if (NULL == (dup->str.ptr = strdup(value->str.ptr))) {
1570
+ agoo_err_set(err, AGOO_ERR_MEMORY, "strdup of length %d failed.", strlen(value->str.ptr));
1571
+ AGOO_FREE(dup);
1572
+ dup = NULL;
1573
+ }
1574
+ } else {
1575
+ memcpy(dup->str.a, value->str.a, sizeof(value->str.a));
1576
+ }
1577
+ break;
1578
+ case GQL_SCALAR_TIME:
1579
+ dup->time = value->time;
1580
+ break;
1581
+ case GQL_SCALAR_UUID:
1582
+ dup->uuid.hi = value->uuid.hi;
1583
+ dup->uuid.lo = value->uuid.lo;
1584
+ break;
1585
+ default:
1586
+ break;
1587
+ }
1588
+ return dup;
1589
+ }
1590
+