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 import std.typecons : TypedefType; 79 static if (isArray!T && !isSomeString!T) 80 alias BaseType = BaseType!(ForeachType!T); 81 else 82 alias BaseType = TypedefType!(Unqual!T); 83 } 84 85 unittest 86 { 87 writeln(" * meta"); 88 writeln("\t * BaseType"); 89 90 static assert(is(BaseType!(int[][][]) == int)); 91 static assert(is(BaseType!(string[]) == string)); 92 static assert(is(BaseType!string == string)); 93 static assert(is(BaseType!dstring == dstring)); 94 } 95 96 template SQLType(T) 97 { 98 alias BT = BaseType!T; 99 100 static if(isInstanceOf!(Nullable, T)) 101 { 102 enum SQLType = SQLType!(Unqual!(typeof(T.get))); 103 //enum isNullable = true; 104 } 105 else 106 { 107 enum isNullable = false; 108 static if(is(T == ubyte[]) || is(T == byte[])) 109 enum SQLType = "BYTEA"; 110 else 111 { 112 static if (isSomeString!BT) 113 enum type = "TEXT"; 114 else static if (is(BT == SysTime)) 115 enum type = "timestamp"; 116 else static if (is(BT == int)) 117 enum type = "INT4"; 118 else static if (is(BT == long)) 119 enum type = "INT8"; 120 else static if (is(BT == short)) 121 enum type = "INT2"; 122 else static if (is(BT == float)) 123 enum type = "FLOAT4"; 124 else static if (is(BT == double)) 125 enum type = "FLOAT8"; 126 else static if (is(BT == bool)) 127 enum type = "BOOL"; 128 else static if (is(BT == char)) 129 enum type = "CHAR(1)"; 130 else static if (is(BT == enum)) 131 enum type = SQLType!(OriginalType!BT); 132 else 133 static assert(false, 134 "Cannot map type \"" ~ T.stringof ~ "\" to any PG type, " ~ 135 "please note that embedded structures need an @embed " ~ 136 "or @type attribute if you do not wish to embed them."); 137 138 static if (isArray!T && !isSomeString!T) 139 enum SQLType = type ~ "[]"; 140 else 141 enum SQLType = type; 142 } 143 } 144 } 145 146 unittest 147 { 148 writeln("\t * SQLType"); 149 150 static assert(SQLType!int == "INT4"); 151 static assert(SQLType!long == "INT8"); 152 static assert(SQLType!float == "FLOAT4"); 153 static assert(SQLType!(int[]) == "INT4[]"); 154 static assert(SQLType!(long[]) == "INT8[]"); 155 static assert(SQLType!(double[]) == "FLOAT8[]"); 156 static assert(SQLType!(string) == "TEXT"); 157 static assert(SQLType!(string[]) == "TEXT[]"); 158 static assert(SQLType!(ubyte[]) == "BYTEA"); 159 160 static assert(SQLType!(Nullable!int) == "INT4"); 161 } 162 163 /** 164 Returns the number of dimensions of the given array type 165 166 Examples: 167 ----------------- 168 auto dims = ArrayDimensions!(int[][]); 169 static assert(dims == 2); 170 ----------------- 171 */ 172 template ArrayDimensions(T) 173 { 174 static if (isArray!T) 175 enum ArrayDimensions = 1 + ArrayDimensions!(ForeachType!T); 176 else 177 enum ArrayDimensions = 0; 178 } 179 180 unittest 181 { 182 writeln("\t * ArrayDimensions"); 183 184 static assert(ArrayDimensions!int == 0); 185 static assert(ArrayDimensions!(int[]) == 1); 186 static assert(ArrayDimensions!(int[][]) == 2); 187 static assert(ArrayDimensions!(int[][][]) == 3); 188 } 189 190 191 /// Removes any Nullable specifiers, even multiple levels 192 template NoNullable(T) 193 { 194 static if (isInstanceOf!(Nullable, T)) 195 // Nullable nullable? Costs us nothing, so why not 196 alias NoNullable = NoNullable!(Unqual!(ReturnType!(T.get))); 197 else 198 alias NoNullable = T; 199 } 200 201 /** 202 Will strip off any Nullable, Typedefs and qualifiers from a given type 203 204 Examples: 205 static assert(RealType!(const Nullable!(immutable int) == int); 206 */ 207 template RealType(T) 208 { 209 import std.typecons : TypedefType; 210 // Ugly, but better than doing this every time we need it 211 alias NT = Unqual!(NoNullable!(TypedefType!T)); 212 213 static if (is(T == NT)) 214 alias RealType = NT; 215 else 216 alias RealType = RealType!NT; 217 } 218 219 template ShouldRecurse(alias TA) 220 { 221 alias T = NoNullable!(typeof(TA)); 222 static if (is(T == class) || is(T == struct)) 223 { 224 static if (hasUDA!(TA, EmbedAttribute)) 225 enum ShouldRecurse = true; 226 else 227 enum ShouldRecurse = false; 228 } 229 else 230 enum ShouldRecurse = false; 231 }