1 module graphql.argumentextractor; 2 3 import std.array : back, empty, popBack; 4 import std.conv : to; 5 import std.format : format; 6 import std.exception : enforce; 7 8 import vibe.data.json; 9 10 import graphql.visitor; 11 import graphql.ast; 12 13 @safe: 14 15 class ArgumentExtractor : Visitor { 16 alias enter = Visitor.enter; 17 alias exit = Visitor.exit; 18 alias accept = Visitor.accept; 19 20 Json arguments; 21 Json variables; 22 23 string[] curNames; 24 25 this(Json variables) { 26 this.variables = variables; 27 this.arguments = Json.emptyObject(); 28 } 29 30 void assign(Json toAssign) @trusted { 31 Json* arg = &this.arguments; 32 //logf("%(%s.%) %s %s", this.curNames, this.arguments, toAssign); 33 assert(!this.curNames.empty); 34 foreach(idx; 0 .. this.curNames.length - 1) { 35 enforce(arg !is null); 36 arg = &((*arg)[this.curNames[idx]]); 37 } 38 39 enforce(arg !is null); 40 41 if(this.curNames.back in (*arg) 42 && ((*arg)[this.curNames.back]).type == Json.Type.array) 43 { 44 ((*arg)[this.curNames.back]) ~= toAssign; 45 } else if((*arg).type == Json.Type.object) { 46 ((*arg)[this.curNames.back]) = toAssign; 47 } else { 48 ((*arg)[this.curNames.back]) = toAssign; 49 } 50 } 51 52 override void enter(const(Argument) arg) { 53 this.curNames ~= arg.name.value; 54 } 55 56 override void exit(const(Argument) arg) { 57 this.curNames.popBack(); 58 } 59 60 override void accept(const(ObjectValues) obj) { 61 enter(obj); 62 final switch(obj.ruleSelection) { 63 case ObjectValuesEnum.V: 64 this.curNames ~= obj.name.value; 65 obj.val.visit(this); 66 this.curNames.popBack(); 67 break; 68 case ObjectValuesEnum.Vsc: 69 this.curNames ~= obj.name.value; 70 obj.val.visit(this); 71 this.curNames.popBack(); 72 obj.follow.visit(this); 73 break; 74 case ObjectValuesEnum.Vs: 75 this.curNames ~= obj.name.value; 76 obj.val.visit(this); 77 this.curNames.popBack(); 78 obj.follow.visit(this); 79 break; 80 } 81 exit(obj); 82 } 83 84 override void enter(const(Variable) var) { 85 string varName = var.name.value; 86 enforce(varName in this.variables, 87 format("Variable with name %s required", varName) 88 ); 89 this.assign(this.variables[varName]); 90 } 91 92 override void enter(const(Value) val) { 93 final switch(val.ruleSelection) { 94 case ValueEnum.STR: 95 this.assign(Json(val.tok.value)); 96 break; 97 case ValueEnum.INT: 98 this.assign(Json(to!long(val.tok.value))); 99 break; 100 case ValueEnum.FLOAT: 101 this.assign(Json(to!double(val.tok.value))); 102 break; 103 case ValueEnum.T: 104 this.assign(Json(true)); 105 break; 106 case ValueEnum.F: 107 this.assign(Json(false)); 108 break; 109 case ValueEnum.ARR: 110 this.assign(Json.emptyArray()); 111 break; 112 case ValueEnum.O: 113 this.assign(Json.emptyObject()); 114 break; 115 case ValueEnum.E: 116 this.assign(Json(val.tok.value)); 117 break; 118 } 119 } 120 } 121