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