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