1 module graphql.reflection;
2 import graphql.traits;
3 import std.traits;
4 import std.meta;
5 import vibe.data.json;
6 
7 @safe:
8 
9 package struct TypeWithStrippedName {
10 	Json typeJson;
11 	string name;
12 	bool canonical;
13 }
14 
15 package struct SchemaReflection(Schema) {
16 	private {
17 		static SchemaReflection _instance;
18 		bool initialized;
19 	}
20 
21 	static SchemaReflection *instance() @safe {
22 		_instance.initialize();
23 		return &_instance;
24 	}
25 
26 	string[TypeInfo] classes;
27 	string[][TypeInfo] derivatives;
28 	string[][string] bases;
29 
30 	TypeWithStrippedName[string] jsonTypes;
31 
32 	private:
33 
34 	void initialize() @safe {
35 		if(initialized) {
36 			return;
37 		}
38 		initialized = true;
39 
40 		execForAllTypes!(Schema, builder)(this);
41 		execForAllTypes!(Schema, builderPhase2)(this);
42 	}
43 }
44 
45 private void builder(T,Schema)(ref SchemaReflection!Schema ths) {
46 	static if(is(T == class)) {
47 		ths.classes[typeid(T)] = T.stringof;
48 		foreach(B; AliasSeq!(T, TransitiveBaseTypeTuple!T)) {
49 			static if(!is(B == Object)) {
50 				ths.derivatives.require(typeid(B), null) ~= T.stringof;
51 				ths.bases.require(T.stringof, null) ~= B.stringof;
52 			}
53 		}
54 	} else static if(is(T == interface)) {
55 		// go through all base types, and set up the derivation lines
56 		foreach(B; AliasSeq!(T, InterfacesTuple!T)) {
57 			ths.derivatives.require(typeid(B), null) ~= T.stringof;
58 			ths.bases.require(T.stringof, null) ~= B.stringof;
59 		}
60 	} else {
61 		// all other types have derivatives and bases of themselves
62 		ths.derivatives.require(typeid(T), null) ~= T.stringof;
63 		ths.bases.require(T.stringof, null) ~= T.stringof;
64 	}
65 }
66 
67 private void builderPhase2(T,Schema)(ref SchemaReflection!Schema ths) {
68 	import graphql.schema.typeconversions : typeToTypeName, typeToJsonImpl;
69 	// build the second parts which need the first parts
70 	alias stripped = stripArrayAndNullable!T;
71 	ths.jsonTypes[typeToTypeName!T] =
72 		TypeWithStrippedName(typeToJsonImpl!(stripped, Schema, T)(),
73 							 stripped.stringof,
74 							 is(stripArrayAndNullable!T == T));
75 }