1 /// 2 module dpq2.conv.from_bson; 3 4 import dpq2.value; 5 import dpq2.oids; 6 import dpq2.result: ArrayProperties, ArrayHeader_net, Dim_net; 7 import dpq2.conv.from_d_types; 8 import dpq2.conv.to_d_types; 9 import vibe.data.bson; 10 import std.bitmanip: nativeToBigEndian; 11 import std.conv: to; 12 13 /// Default type will be used for NULL value and for array without detected type 14 Value bsonToValue(Bson v, OidType defaultType = OidType.Undefined) 15 { 16 if(v.type == Bson.Type.array) 17 return bsonArrayToValue(v, defaultType); 18 else 19 return bsonValueToValue(v, defaultType); 20 } 21 22 private: 23 24 Value bsonValueToValue(Bson v, OidType defaultType) 25 { 26 Value ret; 27 28 with(Bson.Type) 29 switch(v.type) 30 { 31 case null_: 32 ret = Value(ValueFormat.BINARY, defaultType); 33 break; 34 35 case Bson.Type.object: 36 ret = v.toJson.toString.toValue; 37 ret.oidType = OidType.Json; 38 break; 39 40 case bool_: 41 ret = v.get!bool.toValue; 42 break; 43 44 case int_: 45 ret = v.get!int.toValue; 46 break; 47 48 case long_: 49 ret = v.get!long.toValue; 50 break; 51 52 case double_: 53 ret = v.get!double.toValue; 54 break; 55 56 case Bson.Type..string: 57 ret = v.get!(immutable(char)[]).toValue; 58 break; 59 60 default: 61 throw new ValueConvException( 62 ConvExceptionType.NOT_IMPLEMENTED, 63 "Format "~v.type.to!(immutable(char)[])~" doesn't supported by Bson to Value converter", 64 __FILE__, __LINE__ 65 ); 66 } 67 68 return ret; 69 } 70 71 unittest 72 { 73 { 74 Value v1 = bsonToValue(Bson(123)); 75 Value v2 = (123).toValue; 76 77 assert(v1.as!int == v2.as!int); 78 } 79 80 { 81 Value v1 = bsonToValue(Bson("Test string")); 82 Value v2 = ("Test string").toValue; 83 84 assert(v1.as!string == v2.as!string); 85 } 86 87 { 88 Value t = bsonToValue(Bson(true)); 89 Value f = bsonToValue(Bson(false)); 90 91 assert(t.as!bool == true); 92 assert(f.as!bool == false); 93 } 94 } 95 96 Value bsonArrayToValue(ref Bson bsonArr, OidType defaultType) 97 { 98 ubyte[] nullValue() pure 99 { 100 ubyte[] ret = [0xff, 0xff, 0xff, 0xff]; //NULL magic number 101 return ret; 102 } 103 104 ubyte[] rawValue(Value v) pure 105 { 106 if(v.isNull) 107 { 108 return nullValue(); 109 } 110 else 111 { 112 return v._data.length.to!uint.nativeToBigEndian ~ v._data; 113 } 114 } 115 116 ArrayProperties ap; 117 ubyte[] rawValues; 118 119 void recursive(ref Bson bsonArr, int dimension) 120 { 121 if(dimension == ap.dimsSize.length) 122 { 123 ap.dimsSize ~= bsonArr.length.to!int; 124 } 125 else 126 { 127 if(ap.dimsSize[dimension] != bsonArr.length) 128 throw new ValueConvException(ConvExceptionType.NOT_ARRAY, "Jagged arrays are unsupported", __FILE__, __LINE__); 129 } 130 131 foreach(bElem; bsonArr) 132 { 133 ap.nElems++; 134 135 switch(bElem.type) 136 { 137 case Bson.Type.array: 138 recursive(bElem, dimension + 1); 139 break; 140 141 case Bson.Type.null_: 142 rawValues ~= nullValue(); 143 break; 144 145 default: 146 Value v = bsonValueToValue(bElem, OidType.Undefined); 147 148 if(ap.OID == OidType.Undefined) 149 { 150 ap.OID = v.oidType; 151 } 152 else 153 { 154 if(ap.OID != v.oidType) 155 throw new ValueConvException( 156 ConvExceptionType.NOT_ARRAY, 157 "Bson (which used for creating "~ap.OID.to!string~" array) also contains value of type "~v.oidType.to!string, 158 __FILE__, __LINE__ 159 ); 160 } 161 162 rawValues ~= rawValue(v); 163 } 164 } 165 } 166 167 recursive(bsonArr, 0); 168 169 if(ap.OID == OidType.Undefined) ap.OID = defaultType.oidConvTo!"element"; 170 171 ArrayHeader_net h; 172 h.ndims = nativeToBigEndian(ap.dimsSize.length.to!int); 173 h.OID = nativeToBigEndian(ap.OID.to!Oid); 174 175 ubyte[] ret; 176 ret ~= (cast(ubyte*) &h)[0 .. h.sizeof]; 177 178 foreach(i; 0 .. ap.dimsSize.length) 179 { 180 Dim_net dim; 181 dim.dim_size = nativeToBigEndian(ap.dimsSize[i]); 182 dim.lbound = nativeToBigEndian!int(1); 183 184 ret ~= (cast(ubyte*) &dim)[0 .. dim.sizeof]; 185 } 186 187 ret ~= rawValues; 188 189 return Value(cast(immutable) ret, ap.OID.oidConvTo!"array", false, ValueFormat.BINARY); 190 } 191 192 unittest 193 { 194 import dpq2.conv.to_bson; 195 196 { 197 Bson bsonArray = Bson( 198 [Bson(123), Bson(155), Bson(null), Bson(0), Bson(null)] 199 ); 200 201 Value v = bsonToValue(bsonArray); 202 203 assert(v.isSupportedArray); 204 assert(v.as!Bson == bsonArray); 205 } 206 207 { 208 Bson bsonArray = Bson([ 209 Bson([Bson(123), Bson(155), Bson(null)]), 210 Bson([Bson(0), Bson(null), Bson(155)]) 211 ]); 212 213 Value v = bsonToValue(bsonArray); 214 215 assert(v.isSupportedArray); 216 assert(v.as!Bson == bsonArray); 217 } 218 219 { 220 Bson bsonArray = Bson([ 221 Bson([Bson(123), Bson(155)]), 222 Bson([Bson(0)]) 223 ]); 224 225 bool exceptionFlag = false; 226 227 try 228 bsonToValue(bsonArray); 229 catch(ValueConvException e) 230 { 231 if(e.type == ConvExceptionType.NOT_ARRAY) 232 exceptionFlag = true; 233 } 234 235 assert(exceptionFlag); 236 } 237 }