16#if DETWS_ENABLE_GRAPHQL
31 char name[DETWS_GQL_NAME_MAX];
39 char name[DETWS_GQL_NAME_MAX];
50 Node nodes[DETWS_GQL_MAX_NODES];
51 Arg args[DETWS_GQL_MAX_ARGS];
52 char strbuf[DETWS_GQL_STRBUF];
59 int scope[DETWS_GQL_MAX_ARGS];
61 detws_gql_resolver_fn resolver;
62 char path[DETWS_GQL_PATH_MAX];
68 if (s_gql.nnodes >= DETWS_GQL_MAX_NODES)
70 s_gql.err = DetwsGqlResult::DETWS_GQL_ERR_LIMIT;
73 Node *n = &s_gql.nodes[s_gql.nnodes];
79 return s_gql.nnodes++;
94 if (c ==
' ' || c ==
'\t' || c ==
'\n' || c ==
'\r' || c ==
',')
98 while (L.p < L.e && *L.p !=
'\n')
109 return L.p < L.e ? *L.p :
'\0';
113void gql_flag_parse_err()
115 if (s_gql.err == DetwsGqlResult::DETWS_GQL_OK)
116 s_gql.err = DetwsGqlResult::DETWS_GQL_ERR_PARSE;
119bool is_name_start(
char c)
121 return (c >=
'A' && c <=
'Z') || (c >=
'a' && c <=
'z') || c ==
'_';
125 return is_name_start(c) || (c >=
'0' && c <=
'9');
128bool parse_name(Lex &L,
char *out)
131 if (L.p >= L.e || !is_name_start(*L.p))
134 while (L.p < L.e && is_name(*L.p))
136 if (i >= DETWS_GQL_NAME_MAX - 1)
138 s_gql.err = DetwsGqlResult::DETWS_GQL_ERR_LIMIT;
148const char *intern(
const char *s,
int len)
150 if (s_gql.str_len + len + 1 > DETWS_GQL_STRBUF)
152 s_gql.err = DetwsGqlResult::DETWS_GQL_ERR_LIMIT;
155 char *dst = s_gql.strbuf + s_gql.str_len;
158 s_gql.str_len += len + 1;
162bool parse_value(Lex &L, DetwsGqlValue *v)
168 char tmp[DETWS_GQL_STRBUF];
170 while (L.p < L.e && *L.p !=
'"')
173 if (ch ==
'\\' && L.p < L.e)
201 if (n >= (
int)
sizeof(tmp) - 1)
203 s_gql.err = DetwsGqlResult::DETWS_GQL_ERR_LIMIT;
210 s_gql.err = DetwsGqlResult::DETWS_GQL_ERR_PARSE;
214 const char *s = intern(tmp, n);
217 v->type = DetwsGqlType::DETWS_GQL_STR;
221 if (c ==
'-' || (c >=
'0' && c <=
'9'))
232 bool is_float =
false;
233 unsigned long long ipart = 0;
235 while (L.p < L.e && *L.p >=
'0' && *L.p <=
'9')
237 ipart = ipart * 10ULL + (unsigned)(*L.p -
'0');
241 fval = (double)ipart;
242 if (L.p < L.e && *L.p ==
'.')
247 while (L.p < L.e && *L.p >=
'0' && *L.p <=
'9')
250 fval += (double)(*L.p -
'0') / scale;
255 if (L.p < L.e && (*L.p ==
'e' || *L.p ==
'E'))
260 if (L.p < L.e && (*L.p ==
'+' || *L.p ==
'-'))
261 eneg = (*L.p++ ==
'-');
263 while (L.p < L.e && *L.p >=
'0' && *L.p <=
'9')
266 ex = (ex < 400) ? ex * 10 + (*L.p -
'0') : ex;
270 for (
int k = 0; k < ex; k++)
272 fval = eneg ? fval / m : fval * m;
276 s_gql.err = DetwsGqlResult::DETWS_GQL_ERR_PARSE;
281 v->type = DetwsGqlType::DETWS_GQL_FLOAT;
282 v->f = neg ? -fval : fval;
286 v->type = DetwsGqlType::DETWS_GQL_INT;
289 v->i = neg ? -(
long long)ipart : (long long)ipart;
295 if (parse_name(L, kw))
297 if (strcmp(kw,
"true") == 0)
299 v->type = DetwsGqlType::DETWS_GQL_BOOL;
303 if (strcmp(kw,
"false") == 0)
305 v->type = DetwsGqlType::DETWS_GQL_BOOL;
309 if (strcmp(kw,
"null") == 0)
311 v->type = DetwsGqlType::DETWS_GQL_NULL;
315 s_gql.err = DetwsGqlResult::DETWS_GQL_ERR_PARSE;
319int parse_selection(Lex &L,
int depth);
321int parse_field(Lex &L,
int depth)
323 int idx = new_node();
326 if (!parse_name(L, s_gql.nodes[idx].name))
328 gql_flag_parse_err();
337 while (peek(L) !=
')')
339 if (s_gql.nargs >= DETWS_GQL_MAX_ARGS)
341 s_gql.err = DetwsGqlResult::DETWS_GQL_ERR_LIMIT;
344 Arg *a = &s_gql.args[s_gql.nargs];
345 if (!parse_name(L, a->name))
347 gql_flag_parse_err();
352 s_gql.err = DetwsGqlResult::DETWS_GQL_ERR_PARSE;
356 if (!parse_value(L, &a->val))
364 s_gql.nodes[idx].first_arg = first;
365 s_gql.nodes[idx].n_args = count;
369 s_gql.nodes[idx].first_child = parse_selection(L, depth + 1);
370 return s_gql.err != DetwsGqlResult::DETWS_GQL_OK ? -1 : idx;
373int parse_selection(Lex &L,
int depth)
375 if (depth > DETWS_GQL_MAX_DEPTH)
377 s_gql.err = DetwsGqlResult::DETWS_GQL_ERR_LIMIT;
382 s_gql.err = DetwsGqlResult::DETWS_GQL_ERR_PARSE;
388 while (peek(L) !=
'}')
392 s_gql.err = DetwsGqlResult::DETWS_GQL_ERR_PARSE;
395 int f = parse_field(L, depth);
401 s_gql.nodes[prev].next_sib = f;
408bool parse_document(Lex &L)
413 char kw[DETWS_GQL_NAME_MAX];
414 if (!parse_name(L, kw) || strcmp(kw,
"query") != 0)
416 s_gql.err = DetwsGqlResult::DETWS_GQL_ERR_PARSE;
421 char opname[DETWS_GQL_NAME_MAX];
422 if (!parse_name(L, opname))
424 gql_flag_parse_err();
429 s_gql.root = parse_selection(L, 1);
430 if (s_gql.err != DetwsGqlResult::DETWS_GQL_OK)
434 s_gql.err = DetwsGqlResult::DETWS_GQL_ERR_PARSE;
448void w_raw(Writer &w,
const char *s,
size_t len)
452 if (w.n + len > w.cap)
457 memcpy(w.o + w.n, s, len);
460void w_str(Writer &w,
const char *s)
462 w_raw(w, s, strnlen(s, w.cap + 1));
464void w_json_str(Writer &w,
const char *s)
467 for (
const char *p = s; *p; p++)
469 unsigned char ch = (
unsigned char)*p;
483 snprintf(u,
sizeof(u),
"\\u%04x", ch);
487 w_raw(w, (
const char *)&ch, 1);
491void w_scalar(Writer &w,
const DetwsGqlValue *v)
496 case DetwsGqlType::DETWS_GQL_INT:
497 snprintf(b,
sizeof(b),
"%lld", v->i);
500 case DetwsGqlType::DETWS_GQL_FLOAT:
501 snprintf(b,
sizeof(b),
"%g", v->f);
504 case DetwsGqlType::DETWS_GQL_BOOL:
505 w_str(w, v->b ?
"true" :
"false");
507 case DetwsGqlType::DETWS_GQL_STR:
508 w_json_str(w, v->s ? v->s :
"");
516void emit_field(Writer &w,
int idx,
int path_len)
518 Node *node = &s_gql.nodes[idx];
524 if (plen + 1 >= DETWS_GQL_PATH_MAX)
529 s_gql.path[plen++] =
'.';
531 int nl = (int)strnlen(node->name, DETWS_GQL_PATH_MAX);
532 if (plen + nl >= DETWS_GQL_PATH_MAX)
537 memcpy(s_gql.path + plen, node->name, nl);
539 s_gql.path[plen] =
'\0';
543 for (
int a = 0; a < node->n_args; a++)
544 if (s_gql.scope_n < DETWS_GQL_MAX_ARGS)
546 s_gql.scope[s_gql.scope_n++] = node->first_arg + a;
550 w_json_str(w, node->name);
553 if (node->first_child >= 0)
557 for (
int c = node->first_child; c >= 0; c = s_gql.nodes[c].next_sib)
562 emit_field(w, c, plen);
569 v.type = DetwsGqlType::DETWS_GQL_NULL;
570 DetwsGqlArgs view = {s_gql.scope, s_gql.scope_n};
571 if (s_gql.resolver && s_gql.resolver(s_gql.path, &view, &v))
577 s_gql.scope_n -= pushed;
578 s_gql.path[path_len] =
'\0';
582bool detws_gql_arg_int(
const DetwsGqlArgs *args,
const char *name,
long long *out)
586 for (
int k = 0; k < args->count; k++)
588 Arg *a = &s_gql.args[args->idx[k]];
589 if (strcmp(a->name, name) == 0 && a->val.type == DetwsGqlType::DETWS_GQL_INT)
597bool detws_gql_arg_str(
const DetwsGqlArgs *args,
const char *name,
const char **out)
601 for (
int k = 0; k < args->count; k++)
603 Arg *a = &s_gql.args[args->idx[k]];
604 if (strcmp(a->name, name) == 0 && a->val.type == DetwsGqlType::DETWS_GQL_STR)
612bool detws_gql_arg_bool(
const DetwsGqlArgs *args,
const char *name,
bool *out)
616 for (
int k = 0; k < args->count; k++)
618 Arg *a = &s_gql.args[args->idx[k]];
619 if (strcmp(a->name, name) == 0 && a->val.type == DetwsGqlType::DETWS_GQL_BOOL)
628DetwsGqlResult detws_graphql_execute(
const char *query,
size_t len, detws_gql_resolver_fn resolver,
char *out,
636 s_gql.err = DetwsGqlResult::DETWS_GQL_OK;
637 s_gql.resolver = resolver;
638 s_gql.path[0] =
'\0';
640 Lex L = {query, query + (query ? len : 0)};
641 if (!query || !out || cap == 0)
642 return DetwsGqlResult::DETWS_GQL_ERR_PARSE;
644 if (!parse_document(L))
647 (s_gql.err == DetwsGqlResult::DETWS_GQL_ERR_LIMIT) ?
"query exceeds a configured limit" :
"syntax error";
648 Writer w = {out, cap, 0,
false};
649 w_str(w,
"{\"errors\":[{\"message\":");
652 if (!w.ovf && w.n < cap)
654 return s_gql.err != DetwsGqlResult::DETWS_GQL_OK ? s_gql.err : DetwsGqlResult::DETWS_GQL_ERR_PARSE;
657 Writer w = {out, cap, 0,
false};
658 w_str(w,
"{\"data\":{");
660 for (
int c = s_gql.root; c >= 0; c = s_gql.nodes[c].next_sib)
668 if (w.ovf || w.n >= cap)
669 return DetwsGqlResult::DETWS_GQL_ERR_OVERFLOW;
671 return DetwsGqlResult::DETWS_GQL_OK;
Zero-heap GraphQL query subset - parser + executor (DETWS_ENABLE_GRAPHQL).