1 module graphql.uda; 2 3 import std.array : empty; 4 import std.traits : isBuiltinType; 5 6 @safe: 7 8 enum TypeKind { 9 UNDEFINED, 10 SCALAR, 11 OBJECT, 12 INTERFACE, 13 UNION, 14 ENUM, 15 INPUT_OBJECT, 16 LIST, 17 NON_NULL 18 } 19 20 struct GQLDUdaData { 21 TypeKind typeKind; 22 GQLDDeprecatedData deprecationInfo; 23 GQLDDescription description; 24 Ignore ignore; 25 IgnoreForInput ignoreForInput; 26 RequiredForInput requiredForInput; 27 } 28 29 enum IgnoreForInput { 30 undefined, 31 yes, 32 no 33 } 34 35 enum RequiredForInput { 36 undefined, 37 yes, 38 no 39 } 40 41 enum Ignore { 42 undefined, 43 yes, 44 no 45 } 46 47 enum IsDeprecated { 48 undefined, 49 yes, 50 no 51 } 52 53 string toStringImpl(T)(T t) { 54 static if(__traits(hasMember, T, "toString")) { 55 return t.toString(); 56 } else { 57 import std.format : format; 58 return format("%s", t); 59 } 60 } 61 62 /* The wrapped 63 T = the wrapped type 64 SerializationFun = the function to use to serialize T 65 */ 66 struct GQLDCustomLeaf(T, alias SerializationFun = toStringImpl!T) { 67 alias Type = T; 68 Type value; 69 alias value this; 70 71 alias Fun = SerializationFun; 72 73 this(Type value) { 74 this.value = value; 75 } 76 77 void opAssign(Type value) { 78 this.value = value; 79 } 80 } 81 82 unittest { 83 import std.datetime : DateTime; 84 import vibe.data.json; 85 86 Json fun(DateTime dt) { 87 return Json(dt.toISOExtString()); 88 } 89 90 auto f = GQLDCustomLeaf!DateTime(); 91 92 GQLDCustomLeaf!DateTime dt = DateTime(1337, 1, 1); 93 } 94 95 unittest { 96 import std.typecons : Nullable, nullable; 97 import std.datetime : DateTime; 98 Nullable!(GQLDCustomLeaf!DateTime) dt; 99 } 100 101 struct GQLDDeprecatedData { 102 IsDeprecated isDeprecated; 103 string deprecationReason; 104 } 105 106 struct GQLDDescription { 107 string text; 108 string getText() const { 109 return text !is null && text.empty ? this.text : ""; 110 } 111 } 112 113 GQLDDeprecatedData GQLDDeprecated(IsDeprecated isDeprecated) { 114 return GQLDDeprecatedData(isDeprecated, ""); 115 } 116 117 GQLDDeprecatedData GQLDDeprecated(IsDeprecated isDeprecated, 118 string deprecationReason) 119 { 120 return GQLDDeprecatedData(isDeprecated, deprecationReason); 121 } 122 123 GQLDUdaData GQLDUda(Args...)(Args args) { 124 GQLDUdaData ret; 125 static foreach(mem; __traits(allMembers, GQLDUdaData)) { 126 static foreach(arg; args) { 127 static if(is(typeof(__traits(getMember, ret, mem)) == 128 typeof(arg))) 129 { 130 __traits(getMember, ret, mem) = arg; 131 } 132 } 133 } 134 return ret; 135 } 136 137 private template isGQLDUdaData(alias Type) { 138 enum isGQLDUdaData = is(typeof(Type) == GQLDUdaData); 139 } 140 141 private template getGQLDUdaData(Type, string mem) { 142 import std.meta : Filter; 143 alias getGQLDUdaData = 144 Filter!(isGQLDUdaData, 145 __traits(getAttributes, __traits(getMember, Type, mem))); 146 } 147 148 private template getGQLDUdaData(Type) { 149 import std.meta : Filter; 150 alias getGQLDUdaData = 151 Filter!(isGQLDUdaData, __traits(getAttributes, Type)); 152 } 153 154 template getUdaData(Type) { 155 static if(isBuiltinType!Type) { 156 enum getUdaData = GQLDUdaData.init; 157 } else { 158 alias GQLDUdaDataAS = getGQLDUdaData!Type; 159 static if(GQLDUdaDataAS.length > 0) { 160 enum getUdaData = GQLDUdaDataAS[0]; 161 } else { 162 enum getUdaData = GQLDUdaData.init; 163 } 164 } 165 } 166 167 template getUdaData(Type, string mem) { 168 alias GQLDUdaDataAS = getGQLDUdaData!(Type, mem); 169 static if(GQLDUdaDataAS.length > 0) { 170 enum getUdaData = GQLDUdaDataAS[0]; 171 } else { 172 enum getUdaData = GQLDUdaData.init; 173 } 174 } 175 176 unittest { 177 @GQLDUda( 178 GQLDDeprecated(IsDeprecated.yes, "Stupid name"), 179 GQLDDescription("You normal test struct") 180 ) 181 struct Foo { 182 @GQLDUda( 183 GQLDDeprecated(IsDeprecated.no, "Very good name"), 184 GQLDDescription("Contains something") 185 ) 186 int bar; 187 188 int args; 189 } 190 191 enum GQLDUdaData fd = getUdaData!Foo; 192 static assert(fd.deprecationInfo.isDeprecated == IsDeprecated.yes); 193 static assert(fd.deprecationInfo.deprecationReason == "Stupid name"); 194 static assert(fd.description.text == "You normal test struct"); 195 196 enum GQLDUdaData bd = getUdaData!(Foo, "bar"); 197 static assert(bd.deprecationInfo.isDeprecated == IsDeprecated.no); 198 static assert(bd.deprecationInfo.deprecationReason == "Very good name"); 199 static assert(bd.description.text == "Contains something"); 200 201 enum GQLDUdaData ad = getUdaData!(Foo, "args"); 202 static assert(ad.deprecationInfo.isDeprecated == IsDeprecated.undefined); 203 static assert(ad.deprecationInfo.deprecationReason == ""); 204 static assert(ad.description.text == ""); 205 }