-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
BsonDocument.cs
172 lines (129 loc) · 5.16 KB
/
BsonDocument.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
using LiteDB.Engine;
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using static LiteDB.Constants;
namespace LiteDB
{
public class BsonDocument : BsonValue, IDictionary<string, BsonValue>
{
public BsonDocument()
: base(BsonType.Document, new Dictionary<string, BsonValue>(StringComparer.OrdinalIgnoreCase))
{
}
public BsonDocument(ConcurrentDictionary<string, BsonValue> dict)
: this()
{
if (dict == null) throw new ArgumentNullException(nameof(dict));
foreach(var element in dict)
{
this.Add(element);
}
}
public BsonDocument(IDictionary<string, BsonValue> dict)
: this()
{
if (dict == null) throw new ArgumentNullException(nameof(dict));
foreach (var element in dict)
{
this.Add(element);
}
}
public new IDictionary<string, BsonValue> RawValue => base.RawValue as IDictionary<string, BsonValue>;
/// <summary>
/// Get/Set position of this document inside database. It's filled when used in Find operation.
/// </summary>
internal PageAddress RawId { get; set; } = PageAddress.Empty;
/// <summary>
/// Get/Set a field for document. Fields are case sensitive
/// </summary>
public override BsonValue this[string key]
{
get
{
return this.RawValue.GetOrDefault(key, BsonValue.Null);
}
set
{
this.RawValue[key] = value ?? BsonValue.Null;
}
}
#region CompareTo
public override int CompareTo(BsonValue other)
{
// if types are different, returns sort type order
if (other.Type != BsonType.Document) return this.Type.CompareTo(other.Type);
var thisKeys = this.Keys.ToArray();
var thisLength = thisKeys.Length;
var otherDoc = other.AsDocument;
var otherKeys = otherDoc.Keys.ToArray();
var otherLength = otherKeys.Length;
var result = 0;
var i = 0;
var stop = Math.Min(thisLength, otherLength);
for (; 0 == result && i < stop; i++)
result = this[thisKeys[i]].CompareTo(otherDoc[thisKeys[i]]);
// are different
if (result != 0) return result;
// test keys length to check which is bigger
if (i == thisLength) return i == otherLength ? 0 : -1;
return 1;
}
#endregion
#region IDictionary
public ICollection<string> Keys => this.RawValue.Keys;
public ICollection<BsonValue> Values => this.RawValue.Values;
public int Count => this.RawValue.Count;
public bool IsReadOnly => false;
public bool ContainsKey(string key) => this.RawValue.ContainsKey(key);
/// <summary>
/// Get all document elements - Return "_id" as first of all (if exists)
/// </summary>
public IEnumerable<KeyValuePair<string, BsonValue>> GetElements()
{
if(this.RawValue.TryGetValue("_id", out var id))
{
yield return new KeyValuePair<string, BsonValue>("_id", id);
}
foreach(var item in this.RawValue.Where(x => x.Key != "_id"))
{
yield return item;
}
}
public void Add(string key, BsonValue value) => this.RawValue.Add(key, value ?? BsonValue.Null);
public bool Remove(string key) => this.RawValue.Remove(key);
public void Clear() => this.RawValue.Clear();
public bool TryGetValue(string key, out BsonValue value) => this.RawValue.TryGetValue(key, out value);
public void Add(KeyValuePair<string, BsonValue> item) => this.Add(item.Key, item.Value);
public bool Contains(KeyValuePair<string, BsonValue> item) => this.RawValue.Contains(item);
public bool Remove(KeyValuePair<string, BsonValue> item) => this.Remove(item.Key);
public IEnumerator<KeyValuePair<string, BsonValue>> GetEnumerator() => this.RawValue.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => this.RawValue.GetEnumerator();
public void CopyTo(KeyValuePair<string, BsonValue>[] array, int arrayIndex)
{
((ICollection<KeyValuePair<string, BsonValue>>)this.RawValue).CopyTo(array, arrayIndex);
}
public void CopyTo(BsonDocument other)
{
foreach(var element in this)
{
other[element.Key] = element.Value;
}
}
#endregion
private int _length = 0;
internal override int GetBytesCount(bool recalc)
{
if (recalc == false && _length > 0) return _length;
var length = 5;
foreach(var element in this.RawValue)
{
length += this.GetBytesCountElement(element.Key, element.Value);
}
return _length = length;
}
}
}