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