1 module dpq.meta;
2 
3 import dpq.attributes;
4 
5 import std.traits;
6 import std.typecons : Nullable;
7 import std.datetime : SysTime;
8 
9 version(unittest) import std.stdio;
10 
11 deprecated("Use SQLType instead, not all array types are supported by sqlType")
12 string sqlType(T)()
13 {
14 	// TODO: More types, embedded structs, Date types
15 
16 	static if (isArray!T)
17 		alias FT = ForeachType!T;
18 	else
19 		alias FT = T;
20 
21 	static if (is(FT == int) || is(FT == ushort))
22 		enum type = "INT";
23 	else static if (is(FT == long) || is(FT == uint))
24 		enum type = "INT8";
25 	else static if (is(FT == short))
26 		enum type = "INT2";
27 	else static if (is(FT == long))
28 		enum type = "BIGINT";
29 	else static if (is(FT == float))
30 		enum type = "FLOAT4";
31 	else static if (is(FT == double))
32 		enum type = "FLOAT8";
33 	else static if (is(FT == char[]) || is(FT == string))
34 		enum type = "TEXT";
35 	else static if (is(FT == bool))
36 		enum type = "BOOL";
37 	else static if (is(FT == char))
38 		enum type = "CHAR(1)";
39 	else static if(is(FT == ubyte[]) || is(FT == byte[]))
40 		enum type = "BYTEA";
41 	else static if (is(FT == enum))
42 		enum type = sqlType!(OriginalType!FT);
43 	else
44 		static assert(false, "Cannot map type \"" ~ T.stringof ~ "\" to any PG type, please specify it manually using @type.");
45 
46 	static if (isArray!T)
47 	{
48 		static if (isStaticArray!T)
49 			return type ~ "[%d]".format(T.length);
50 		else
51 			return type ~ "[]";
52 	}
53 	else
54 		return type;
55 }
56 
57 /**
58 	Returns the array's base type
59 
60 	Returns the string type for any type that returns true
61 	for isSomeString!T
62 
63 	Examples:
64 	---------------
65 	alias T = BaseType!(int[][]);
66 	alias T2 = BaseType!(int[]);
67 	alias T3 = BaseType!int;
68 	alias T4 = BaseType!(string[])
69 
70 	static assert(is(T == int));
71 	static assert(is(T2 == int));
72 	static assert(is(T3 == int));
73 	static assert(is(T4 == string));
74 	---------------
75 */
76 template BaseType(T)
77 {
78 	static if (isArray!T && !isSomeString!T)
79 		alias BaseType = BaseType!(ForeachType!T);
80 	else
81 		alias BaseType = Unqual!T;
82 }
83 
84 unittest
85 {
86 	writeln(" * meta");
87 	writeln("\t * BaseType");
88 
89 	static assert(is(BaseType!(int[][][]) == int));
90 	static assert(is(BaseType!(string[]) == string));
91 	static assert(is(BaseType!string == string));
92 	static assert(is(BaseType!dstring == dstring));
93 }
94 
95 template SQLType(T)
96 {
97 	alias BT = BaseType!T;
98 
99 	static if(isInstanceOf!(Nullable, T))
100 	{
101 		enum SQLType = SQLType!(Unqual!(typeof(T.get)));
102 		//enum isNullable = true;
103 	}
104 	else
105 	{
106 		enum isNullable = false;
107 		static if(is(T == ubyte[]) || is(T == byte[]))
108 			enum SQLType = "BYTEA";
109 		else
110 		{
111 			static if (isSomeString!BT)
112 				enum type = "TEXT";
113 			else static if (is(BT == SysTime))
114 				enum type = "timestamp";
115 			else static if (is(BT == int))
116 				enum type = "INT4";
117 			else static if (is(BT == long))
118 				enum type = "INT8";
119 			else static if (is(BT == short))
120 				enum type = "INT2";
121 			else static if (is(BT == float))
122 				enum type = "FLOAT4";
123 			else static if (is(BT == double))
124 				enum type = "FLOAT8";
125 			else static if (is(BT == bool))
126 				enum type = "BOOL";
127 			else static if (is(BT == char))
128 				enum type = "CHAR(1)";
129 			else static if (is(BT == enum))
130 				enum type = SQLType!(OriginalType!BT);
131 			else
132 				static assert(false,
133 						"Cannot map type \"" ~ T.stringof ~ "\" to any PG type, " ~
134 						"please note that embedded structures need an @embed " ~
135 						"or @type attribute if you do not wish to embed them.");
136 
137 			static if (isArray!T && !isSomeString!T)
138 				enum SQLType = type ~ "[]";
139 			else 
140 				enum SQLType = type;
141 		}
142 	}
143 }
144 
145 unittest
146 {
147 	writeln("\t * SQLType");
148 
149 	static assert(SQLType!int == "INT4");
150 	static assert(SQLType!long == "INT8");
151 	static assert(SQLType!float == "FLOAT4");
152 	static assert(SQLType!(int[]) == "INT4[]");
153 	static assert(SQLType!(long[]) == "INT8[]");
154 	static assert(SQLType!(double[]) == "FLOAT8[]");
155 	static assert(SQLType!(string) == "TEXT");
156 	static assert(SQLType!(string[]) == "TEXT[]");
157 	static assert(SQLType!(ubyte[]) == "BYTEA");
158 
159 	static assert(SQLType!(Nullable!int) == "INT4");
160 }
161 
162 /**
163 	Returns the number of dimensions of the given array type
164 
165 	Examples:
166 	-----------------
167 	auto dims = ArrayDimensions!(int[][]);
168 	static assert(dims == 2);
169 	-----------------
170  */
171 template ArrayDimensions(T)
172 {
173 	static if (isArray!T)
174 		enum ArrayDimensions = 1 + ArrayDimensions!(ForeachType!T);
175 	else 
176 		enum ArrayDimensions = 0;
177 }
178 
179 unittest
180 {
181 	writeln("\t * ArrayDimensions");
182 
183 	static assert(ArrayDimensions!int == 0);
184 	static assert(ArrayDimensions!(int[]) == 1);
185 	static assert(ArrayDimensions!(int[][]) == 2);
186 	static assert(ArrayDimensions!(int[][][]) == 3);
187 }
188 
189 
190 template ShouldRecurse(alias TA)
191 {
192 	alias T = typeof(TA);
193 	static if (is(T == class) || is(T == struct))
194 		static if (hasUDA!(TA, EmbedAttribute))
195 			enum ShouldRecurse = true;
196 		else
197 			enum ShouldRecurse = false;
198 	else
199 		enum ShouldRecurse = false;
200 }