Skip to content

Commit

Permalink
Changed default to UTC dates. Exposed some BsonReader/Writer internal…
Browse files Browse the repository at this point in the history
…s to make it easier to customize serialization buffers.
  • Loading branch information
rejemy committed Apr 29, 2020
1 parent 444dd83 commit c38f50e
Show file tree
Hide file tree
Showing 17 changed files with 143 additions and 84 deletions.
29 changes: 11 additions & 18 deletions UltraLiteDB/Document/Bson/BsonReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,28 @@ namespace UltraLiteDB
/// <summary>
/// Internal class to deserialize a byte[] into a BsonDocument using BSON data format
/// </summary>
internal class BsonReader
public static class BsonReader
{
private bool _utcDate = false;

public BsonReader(bool utcDate)
{
_utcDate = utcDate;
}

/// <summary>
/// Main method - deserialize using ByteReader helper
/// </summary>
public BsonDocument Deserialize(byte[] bson)
public static BsonDocument Deserialize(byte[] bson, bool utcDate = true)
{
return this.ReadDocument(new ByteReader(bson));
return ReadDocument(new ByteReader(bson), utcDate);
}

/// <summary>
/// Read a BsonDocument from reader
/// </summary>
public BsonDocument ReadDocument(ByteReader reader)
public static BsonDocument ReadDocument(ByteReader reader, bool utcDate = true)
{
var length = reader.ReadInt32();
var end = reader.Position + length - 5;
var obj = new BsonDocument();

while (reader.Position < end)
{
var value = this.ReadElement(reader, out string name);
var value = ReadElement(reader, out string name, utcDate);
obj.RawValue[name] = value;
}

Expand All @@ -46,15 +39,15 @@ public BsonDocument ReadDocument(ByteReader reader)
/// <summary>
/// Read an BsonArray from reader
/// </summary>
public BsonArray ReadArray(ByteReader reader)
public static BsonArray ReadArray(ByteReader reader, bool utcDate = true)
{
var length = reader.ReadInt32();
var end = reader.Position + length - 5;
var arr = new BsonArray();

while (reader.Position < end)
{
var value = this.ReadElement(reader, out string name);
var value = ReadElement(reader, out string name, utcDate);
arr.Add(value);
}

Expand All @@ -66,7 +59,7 @@ public BsonArray ReadArray(ByteReader reader)
/// <summary>
/// Reads an element (key-value) from an reader
/// </summary>
private BsonValue ReadElement(ByteReader reader, out string name)
private static BsonValue ReadElement(ByteReader reader, out string name, bool utcDate)
{
var type = reader.ReadByte();
name = reader.ReadCString();
Expand All @@ -81,11 +74,11 @@ private BsonValue ReadElement(ByteReader reader, out string name)
}
else if (type == 0x03) // Document
{
return this.ReadDocument(reader);
return ReadDocument(reader, utcDate);
}
else if (type == 0x04) // Array
{
return this.ReadArray(reader);
return ReadArray(reader, utcDate);
}
else if (type == 0x05) // Binary
{
Expand Down Expand Up @@ -117,7 +110,7 @@ private BsonValue ReadElement(ByteReader reader, out string name)

var date = BsonValue.UnixEpoch.AddMilliseconds(ts);

return _utcDate ? date : date.ToLocalTime();
return utcDate ? date : date.ToLocalTime();
}
else if (type == 0x0A) // Null
{
Expand Down
18 changes: 11 additions & 7 deletions UltraLiteDB/Document/Bson/BsonSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,28 @@ namespace UltraLiteDB
/// <summary>
/// Class to call method for convert BsonDocument to/from byte[] - based on http://bsonspec.org/spec.html
/// </summary>
public class BsonSerializer
public static class BsonSerializer
{
public static byte[] Serialize(BsonDocument doc)
{
if (doc == null) throw new ArgumentNullException(nameof(doc));

var writer = new BsonWriter();

return writer.Serialize(doc);
return BsonWriter.Serialize(doc);
}

public static BsonDocument Deserialize(byte[] bson, bool utcDate = false)
public static int SerializeTo(BsonDocument doc, byte[] array)
{
if (bson == null || bson.Length == 0) throw new ArgumentNullException(nameof(bson));
if (doc == null) throw new ArgumentNullException(nameof(doc));

return BsonWriter.SerializeTo(doc, array);
}

var reader = new BsonReader(utcDate);
public static BsonDocument Deserialize(byte[] bson, bool utcDate = true)
{
if (bson == null || bson.Length == 0) throw new ArgumentNullException(nameof(bson));

return reader.Deserialize(bson);
return BsonReader.Deserialize(bson, utcDate);
}
}
}
69 changes: 41 additions & 28 deletions UltraLiteDB/Document/Bson/BsonWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,80 +7,93 @@ namespace UltraLiteDB
/// <summary>
/// Internal class to serialize a BsonDocument to BSON data format (byte[])
/// </summary>
internal class BsonWriter
public static class BsonWriter
{
/// <summary>
/// Main method - serialize document. Uses ByteWriter
/// </summary>
public byte[] Serialize(BsonDocument doc)
public static byte[] Serialize(BsonDocument doc)
{
var count = doc.GetBytesCount(true);
var writer = new ByteWriter(count);

this.WriteDocument(writer, doc);
WriteDocument(writer, doc);

return writer.Buffer;
}

public static int SerializeTo(BsonDocument doc, byte[] array)
{
var count = doc.GetBytesCount(true);
if(count > array.Length)
throw new ArgumentException("Array not large enough to hold encoded BsonDocument");

var writer = new ByteWriter(array);

WriteDocument(writer, doc);

return count;
}

/// <summary>
/// Write a bson document
/// </summary>
public void WriteDocument(ByteWriter writer, BsonDocument doc)
public static void WriteDocument(ByteWriter writer, BsonDocument doc)
{
writer.Write(doc.GetBytesCount(false));

foreach (var key in doc.Keys)
{
this.WriteElement(writer, key, doc[key] ?? BsonValue.Null);
WriteElement(writer, key, doc[key] ?? BsonValue.Null);
}

writer.Write((byte)0x00);
}

public void WriteArray(ByteWriter writer, BsonArray array)
public static void WriteArray(ByteWriter writer, BsonArray array)
{
writer.Write(array.GetBytesCount(false));

for (var i = 0; i < array.Count; i++)
{
this.WriteElement(writer, i.ToString(), array[i] ?? BsonValue.Null);
WriteElement(writer, i.ToString(), array[i] ?? BsonValue.Null);
}

writer.Write((byte)0x00);
}

private void WriteElement(ByteWriter writer, string key, BsonValue value)
private static void WriteElement(ByteWriter writer, string key, BsonValue value)
{
// cast RawValue to avoid one if on As<Type>
switch (value.Type)
{
case BsonType.Double:
writer.Write((byte)0x01);
this.WriteCString(writer, key);
WriteCString(writer, key);
writer.Write((Double)value.RawValue);
break;

case BsonType.String:
writer.Write((byte)0x02);
this.WriteCString(writer, key);
this.WriteString(writer, (String)value.RawValue);
WriteCString(writer, key);
WriteString(writer, (String)value.RawValue);
break;

case BsonType.Document:
writer.Write((byte)0x03);
this.WriteCString(writer, key);
this.WriteDocument(writer, (BsonDocument)value);
WriteCString(writer, key);
WriteDocument(writer, (BsonDocument)value);
break;

case BsonType.Array:
writer.Write((byte)0x04);
this.WriteCString(writer, key);
this.WriteArray(writer, new BsonArray((List<BsonValue>)value.RawValue));
WriteCString(writer, key);
WriteArray(writer, new BsonArray((List<BsonValue>)value.RawValue));
break;

case BsonType.Binary:
writer.Write((byte)0x05);
this.WriteCString(writer, key);
WriteCString(writer, key);
var bytes = (byte[])value.RawValue;
writer.Write(bytes.Length);
writer.Write((byte)0x00); // subtype 00 - Generic binary subtype
Expand All @@ -89,7 +102,7 @@ private void WriteElement(ByteWriter writer, string key, BsonValue value)

case BsonType.Guid:
writer.Write((byte)0x05);
this.WriteCString(writer, key);
WriteCString(writer, key);
var guid = ((Guid)value.RawValue).ToByteArray();
writer.Write(guid.Length);
writer.Write((byte)0x04); // UUID
Expand All @@ -98,19 +111,19 @@ private void WriteElement(ByteWriter writer, string key, BsonValue value)

case BsonType.ObjectId:
writer.Write((byte)0x07);
this.WriteCString(writer, key);
WriteCString(writer, key);
writer.Write(((ObjectId)value.RawValue).ToByteArray());
break;

case BsonType.Boolean:
writer.Write((byte)0x08);
this.WriteCString(writer, key);
WriteCString(writer, key);
writer.Write((byte)(((Boolean)value.RawValue) ? 0x01 : 0x00));
break;

case BsonType.DateTime:
writer.Write((byte)0x09);
this.WriteCString(writer, key);
WriteCString(writer, key);
var date = (DateTime)value.RawValue;
// do not convert to UTC min/max date values - #19
var utc = (date == DateTime.MinValue || date == DateTime.MaxValue) ? date : date.ToUniversalTime();
Expand All @@ -120,48 +133,48 @@ private void WriteElement(ByteWriter writer, string key, BsonValue value)

case BsonType.Null:
writer.Write((byte)0x0A);
this.WriteCString(writer, key);
WriteCString(writer, key);
break;

case BsonType.Int32:
writer.Write((byte)0x10);
this.WriteCString(writer, key);
WriteCString(writer, key);
writer.Write((Int32)value.RawValue);
break;

case BsonType.Int64:
writer.Write((byte)0x12);
this.WriteCString(writer, key);
WriteCString(writer, key);
writer.Write((Int64)value.RawValue);
break;

case BsonType.Decimal:
writer.Write((byte)0x13);
this.WriteCString(writer, key);
WriteCString(writer, key);
writer.Write((Decimal)value.RawValue);
break;

case BsonType.MinValue:
writer.Write((byte)0xFF);
this.WriteCString(writer, key);
WriteCString(writer, key);
break;

case BsonType.MaxValue:
writer.Write((byte)0x7F);
this.WriteCString(writer, key);
WriteCString(writer, key);
break;
}
}

private void WriteString(ByteWriter writer, string s)
private static void WriteString(ByteWriter writer, string s)
{
var bytes = Encoding.UTF8.GetBytes(s);
writer.Write(bytes.Length + 1);
writer.Write(bytes);
writer.Write((byte)0x00);
}

private void WriteCString(ByteWriter writer, string s)
private static void WriteCString(ByteWriter writer, string s)
{
var bytes = Encoding.UTF8.GetBytes(s);
writer.Write(bytes);
Expand Down
4 changes: 2 additions & 2 deletions UltraLiteDB/Document/BsonValue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -584,8 +584,8 @@ public bool Equals(BsonValue other)

public static bool operator ==(BsonValue lhs, BsonValue rhs)
{
if (object.ReferenceEquals(lhs, null)) return object.ReferenceEquals(rhs, null);
if (object.ReferenceEquals(rhs, null)) return false; // don't check type because sometimes different types can be ==
if (object.ReferenceEquals(lhs, null)) return object.ReferenceEquals(rhs, null) || rhs.IsNull;
if (object.ReferenceEquals(rhs, null)) return object.ReferenceEquals(lhs, null) || lhs.IsNull;

return lhs.Equals(rhs);
}
Expand Down
2 changes: 1 addition & 1 deletion UltraLiteDB/Document/Json/JsonSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace UltraLiteDB
/// <summary>
/// Static class for serialize/deserialize BsonDocuments into json extended format
/// </summary>
public class JsonSerializer
public static class JsonSerializer
{
#region Serialize

Expand Down
4 changes: 2 additions & 2 deletions UltraLiteDB/Engine/Engine/Aggregate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public long Count(string collection, Query query = null)
{
// count distinct documents
return nodes
.Select(x => _bsonReader.Deserialize(_data.Read(x.DataBlock)).AsDocument)
.Select(x => BsonReader.Deserialize(_data.Read(x.DataBlock)).AsDocument)
.Where(x => query.FilterDocument(x))
.Distinct()
.LongCount();
Expand Down Expand Up @@ -112,7 +112,7 @@ public bool Exists(string collection, Query query)
{
// check if has at least first document
return nodes
.Select(x => _bsonReader.Deserialize(_data.Read(x.DataBlock)).AsDocument)
.Select(x => BsonReader.Deserialize(_data.Read(x.DataBlock)).AsDocument)
.Where(x => query.FilterDocument(x))
.Any();
}
Expand Down
2 changes: 1 addition & 1 deletion UltraLiteDB/Engine/Engine/Delete.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public int Delete(string collection, Query query)
if (query.UseFilter)
{
var buffer = _data.Read(node.DataBlock);
var doc = _bsonReader.Deserialize(buffer).AsDocument;
var doc = BsonReader.Deserialize(buffer).AsDocument;
if (query.FilterDocument(doc) == false) continue;
}
Expand Down
4 changes: 2 additions & 2 deletions UltraLiteDB/Engine/Engine/Find.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public IEnumerable<BsonDocument> Find(string collection, Query query, int skip =
_log.Write(Logger.QUERY, "{0} :: {1}", collection, query);

// fill buffer with documents
cursor.Fetch(_trans, _data, _bsonReader);
cursor.Fetch(_trans, _data);


// returing first documents in buffer
Expand All @@ -41,7 +41,7 @@ public IEnumerable<BsonDocument> Find(string collection, Query query, int skip =
while (cursor.HasMore)
{

cursor.Fetch(_trans, _data, _bsonReader);
cursor.Fetch(_trans, _data);


// return documents from buffer
Expand Down
Loading

0 comments on commit c38f50e

Please sign in to comment.