Skip to content

Commit 4326061

Browse files
author
rstam
committed
CSHARP-995: Add support for reading the new extended JSON formats added in server 2.6.
1 parent 98bd11c commit 4326061

File tree

3 files changed

+345
-9
lines changed

3 files changed

+345
-9
lines changed

MongoDB.Bson/IO/JsonReader.cs

Lines changed: 147 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,19 @@ public override BsonType ReadBsonType<TValue>(BsonTrie<TValue> bsonTrie, out boo
237237
CurrentBsonType = BsonType.DateTime;
238238
_currentValue = ParseISODateTimeConstructor();
239239
break;
240+
case "MaxKey":
241+
CurrentBsonType = BsonType.MaxKey;
242+
_currentValue = BsonMaxKey.Value;
243+
break;
244+
case "MinKey":
245+
CurrentBsonType = BsonType.MinKey;
246+
_currentValue = BsonMinKey.Value;
247+
break;
248+
case "Number":
249+
case "NumberInt":
250+
CurrentBsonType = BsonType.Int32;
251+
_currentValue = ParseNumberConstructor();
252+
break;
240253
case "NumberLong":
241254
CurrentBsonType = BsonType.Int64;
242255
_currentValue = ParseNumberLongConstructor();
@@ -249,6 +262,10 @@ public override BsonType ReadBsonType<TValue>(BsonTrie<TValue> bsonTrie, out boo
249262
CurrentBsonType = BsonType.RegularExpression;
250263
_currentValue = ParseRegularExpressionConstructor();
251264
break;
265+
case "Timestamp":
266+
CurrentBsonType = BsonType.Timestamp;
267+
_currentValue = ParseTimestampConstructor();
268+
break;
252269
case "UUID":
253270
case "GUID":
254271
case "CSUUID":
@@ -1036,12 +1053,14 @@ private BsonType ParseExtendedJson()
10361053
case "$binary": _currentValue = ParseBinDataExtendedJson(); return BsonType.Binary;
10371054
case "$code": return ParseJavaScriptExtendedJson(out _currentValue);
10381055
case "$date": _currentValue = ParseDateTimeExtendedJson(); return BsonType.DateTime;
1039-
case "$maxkey": _currentValue = ParseMaxKeyExtendedJson(); return BsonType.MaxKey;
1040-
case "$minkey": _currentValue = ParseMinKeyExtendedJson(); return BsonType.MinKey;
1056+
case "$maxkey": case "$maxKey": _currentValue = ParseMaxKeyExtendedJson(); return BsonType.MaxKey;
1057+
case "$minkey": case "$minKey": _currentValue = ParseMinKeyExtendedJson(); return BsonType.MinKey;
1058+
case "$numberLong": _currentValue = ParseNumberLongExtendedJson(); return BsonType.Int64;
10411059
case "$oid": _currentValue = ParseObjectIdExtendedJson(); return BsonType.ObjectId;
10421060
case "$regex": _currentValue = ParseRegularExpressionExtendedJson(); return BsonType.RegularExpression;
10431061
case "$symbol": _currentValue = ParseSymbolExtendedJson(); return BsonType.Symbol;
10441062
case "$timestamp": _currentValue = ParseTimestampExtendedJson(); return BsonType.Timestamp;
1063+
case "$undefined": _currentValue = ParseUndefinedExtendedJson(); return BsonType.Undefined;
10451064
}
10461065
}
10471066
PushToken(nameToken);
@@ -1242,6 +1261,9 @@ private BsonType ParseNew(out BsonValue value)
12421261
case "ISODate":
12431262
value = ParseISODateTimeConstructor();
12441263
return BsonType.DateTime;
1264+
case "NumberInt":
1265+
value = ParseNumberConstructor();
1266+
return BsonType.Int32;
12451267
case "NumberLong":
12461268
value = ParseNumberLongConstructor();
12471269
return BsonType.Int64;
@@ -1251,6 +1273,9 @@ private BsonType ParseNew(out BsonValue value)
12511273
case "RegExp":
12521274
value = ParseRegularExpressionConstructor();
12531275
return BsonType.RegularExpression;
1276+
case "Timestamp":
1277+
value = ParseTimestampConstructor();
1278+
return BsonType.Timestamp;
12541279
case "UUID":
12551280
case "GUID":
12561281
case "CSUUID":
@@ -1267,6 +1292,28 @@ private BsonType ParseNew(out BsonValue value)
12671292
}
12681293
}
12691294

1295+
private BsonValue ParseNumberConstructor()
1296+
{
1297+
VerifyToken("(");
1298+
var valueToken = PopToken();
1299+
int value;
1300+
if (valueToken.IsNumber)
1301+
{
1302+
value = valueToken.Int32Value;
1303+
}
1304+
else if (valueToken.Type == JsonTokenType.String)
1305+
{
1306+
value = int.Parse(valueToken.StringValue);
1307+
}
1308+
else
1309+
{
1310+
var message = string.Format("JSON reader expected an integer or a string but found '{0}'.", valueToken.Lexeme);
1311+
throw new FileFormatException(message);
1312+
}
1313+
VerifyToken(")");
1314+
return new BsonInt32(value);
1315+
}
1316+
12701317
private BsonValue ParseNumberLongConstructor()
12711318
{
12721319
VerifyToken("(");
@@ -1289,6 +1336,19 @@ private BsonValue ParseNumberLongConstructor()
12891336
return new BsonInt64(value);
12901337
}
12911338

1339+
private BsonValue ParseNumberLongExtendedJson()
1340+
{
1341+
VerifyToken(":");
1342+
var valueToken = PopToken();
1343+
if (valueToken.Type != JsonTokenType.String)
1344+
{
1345+
var message = string.Format("JSON reader expected a string but found '{0}'.", valueToken.Lexeme);
1346+
throw new FileFormatException(message);
1347+
}
1348+
VerifyToken("}");
1349+
return new BsonInt64(long.Parse(valueToken.StringValue));
1350+
}
1351+
12921352
private BsonValue ParseObjectIdConstructor()
12931353
{
12941354
VerifyToken("(");
@@ -1388,10 +1448,86 @@ private BsonValue ParseSymbolExtendedJson()
13881448
return new BsonString(nameToken.StringValue); // will be converted to a BsonSymbol at a higher level
13891449
}
13901450

1451+
private BsonValue ParseTimestampConstructor()
1452+
{
1453+
VerifyToken("(");
1454+
int secondsSinceEpoch;
1455+
var secondsSinceEpochToken = PopToken();
1456+
if (secondsSinceEpochToken.IsNumber)
1457+
{
1458+
secondsSinceEpoch = secondsSinceEpochToken.Int32Value;
1459+
}
1460+
else
1461+
{
1462+
var message = string.Format("JSON reader expected a number but found '{0}'.", secondsSinceEpochToken.Lexeme);
1463+
throw new FileFormatException(message);
1464+
}
1465+
VerifyToken(",");
1466+
int increment;
1467+
var incrementToken = PopToken();
1468+
if (secondsSinceEpochToken.IsNumber)
1469+
{
1470+
increment = incrementToken.Int32Value;
1471+
}
1472+
else
1473+
{
1474+
var message = string.Format("JSON reader expected a number but found '{0}'.", secondsSinceEpochToken.Lexeme);
1475+
throw new FileFormatException(message);
1476+
}
1477+
VerifyToken(")");
1478+
return new BsonTimestamp(secondsSinceEpoch, increment);
1479+
}
1480+
13911481
private BsonValue ParseTimestampExtendedJson()
13921482
{
13931483
VerifyToken(":");
1394-
var valueToken = PopToken();
1484+
var nextToken = PopToken();
1485+
if (nextToken.Type == JsonTokenType.BeginObject)
1486+
{
1487+
return ParseTimestampExtendedJsonNewRepresentation();
1488+
}
1489+
else
1490+
{
1491+
return ParseTimestampExtendedJsonOldRepresentation(nextToken);
1492+
}
1493+
}
1494+
1495+
private BsonValue ParseTimestampExtendedJsonNewRepresentation()
1496+
{
1497+
VerifyString("t");
1498+
VerifyToken(":");
1499+
var secondsSinceEpochToken = PopToken();
1500+
int secondsSinceEpoch;
1501+
if (secondsSinceEpochToken.IsNumber)
1502+
{
1503+
secondsSinceEpoch = secondsSinceEpochToken.Int32Value;
1504+
}
1505+
else
1506+
{
1507+
var message = string.Format("JSON reader expected an integer but found '{0}'.", secondsSinceEpochToken.Lexeme);
1508+
throw new FileFormatException(message);
1509+
}
1510+
VerifyToken(",");
1511+
VerifyString("i");
1512+
VerifyToken(":");
1513+
var incrementToken = PopToken();
1514+
int increment;
1515+
if (incrementToken.IsNumber)
1516+
{
1517+
increment = incrementToken.Int32Value;
1518+
}
1519+
else
1520+
{
1521+
var message = string.Format("JSON reader expected an integer but found '{0}'.", incrementToken.Lexeme);
1522+
throw new FileFormatException(message);
1523+
}
1524+
VerifyToken("}");
1525+
VerifyToken("}");
1526+
return new BsonTimestamp(secondsSinceEpoch, increment);
1527+
}
1528+
1529+
private BsonValue ParseTimestampExtendedJsonOldRepresentation(JsonToken valueToken)
1530+
{
13951531
long value;
13961532
if (valueToken.Type == JsonTokenType.Int32 || valueToken.Type == JsonTokenType.Int64)
13971533
{
@@ -1410,6 +1546,14 @@ private BsonValue ParseTimestampExtendedJson()
14101546
return new BsonTimestamp(value);
14111547
}
14121548

1549+
private BsonValue ParseUndefinedExtendedJson()
1550+
{
1551+
VerifyToken(":");
1552+
VerifyToken("true");
1553+
VerifyToken("}");
1554+
return BsonMaxKey.Value;
1555+
}
1556+
14131557
private BsonValue ParseUUIDConstructor(string uuidConstructorName)
14141558
{
14151559
VerifyToken("(");

MongoDB.Bson/IO/JsonToken.cs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,17 @@ public virtual long Int64Value
166166
get { throw new NotSupportedException(); }
167167
}
168168

169+
/// <summary>
170+
/// Gets a value indicating whether this token is number.
171+
/// </summary>
172+
/// <value>
173+
/// <c>true</c> if this token is number; otherwise, <c>false</c>.
174+
/// </value>
175+
public virtual bool IsNumber
176+
{
177+
get { return false; }
178+
}
179+
169180
/// <summary>
170181
/// Gets the value of an ObjectId token.
171182
/// </summary>
@@ -249,6 +260,33 @@ public override double DoubleValue
249260
{
250261
get { return _value; }
251262
}
263+
264+
/// <summary>
265+
/// Gets the value of an Int32 token.
266+
/// </summary>
267+
public override int Int32Value
268+
{
269+
get { return (int)_value; }
270+
}
271+
272+
/// <summary>
273+
/// Gets the value of an Int64 token.
274+
/// </summary>
275+
public override long Int64Value
276+
{
277+
get { return (long)_value; }
278+
}
279+
280+
/// <summary>
281+
/// Gets a value indicating whether this token is number.
282+
/// </summary>
283+
/// <value>
284+
/// <c>true</c> if this token is number; otherwise, <c>false</c>.
285+
/// </value>
286+
public override bool IsNumber
287+
{
288+
get { return true; }
289+
}
252290
}
253291

254292
/// <summary>
@@ -272,6 +310,14 @@ public Int32JsonToken(string lexeme, int value)
272310
}
273311

274312
// public properties
313+
/// <summary>
314+
/// Gets the value of a Double token.
315+
/// </summary>
316+
public override double DoubleValue
317+
{
318+
get { return _value; }
319+
}
320+
275321
/// <summary>
276322
/// Gets the value of an Int32 token.
277323
/// </summary>
@@ -287,6 +333,17 @@ public override long Int64Value
287333
{
288334
get { return _value; }
289335
}
336+
337+
/// <summary>
338+
/// Gets a value indicating whether this token is number.
339+
/// </summary>
340+
/// <value>
341+
/// <c>true</c> if this token is number; otherwise, <c>false</c>.
342+
/// </value>
343+
public override bool IsNumber
344+
{
345+
get { return true; }
346+
}
290347
}
291348

292349
/// <summary>
@@ -310,13 +367,40 @@ public Int64JsonToken(string lexeme, long value)
310367
}
311368

312369
// public properties
370+
/// <summary>
371+
/// Gets the value of a Double token.
372+
/// </summary>
373+
public override double DoubleValue
374+
{
375+
get { return _value; }
376+
}
377+
378+
/// <summary>
379+
/// Gets the value of an Int32 token.
380+
/// </summary>
381+
public override int Int32Value
382+
{
383+
get { return (int)_value; }
384+
}
385+
313386
/// <summary>
314387
/// Gets the value of an Int64 token.
315388
/// </summary>
316389
public override long Int64Value
317390
{
318391
get { return _value; }
319392
}
393+
394+
/// <summary>
395+
/// Gets a value indicating whether this token is number.
396+
/// </summary>
397+
/// <value>
398+
/// <c>true</c> if this token is number; otherwise, <c>false</c>.
399+
/// </value>
400+
public override bool IsNumber
401+
{
402+
get { return true; }
403+
}
320404
}
321405

322406
/// <summary>

0 commit comments

Comments
 (0)