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 }