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