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