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