• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

b1f6c1c4 / ProfessionalAccounting / 327

28 Apr 2025 05:37PM UTC coverage: 51.346% (-3.0%) from 54.325%
327

push

appveyor

b1f6c1c4
ci buildx

6620 of 12893 relevant lines covered (51.35%)

126.37 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

70.69
/AccountingServer.DAL/Serializer/SerializationHelper.cs
1
/* Copyright (C) 2020-2025 b1f6c1c4
2
 *
3
 * This file is part of ProfessionalAccounting.
4
 *
5
 * ProfessionalAccounting is free software: you can redistribute it and/or
6
 * modify it under the terms of the GNU Affero General Public License as
7
 * published by the Free Software Foundation, version 3.
8
 *
9
 * ProfessionalAccounting is distributed in the hope that it will be useful, but
10
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License
12
 * for more details.
13
 *
14
 * You should have received a copy of the GNU Affero General Public License
15
 * along with ProfessionalAccounting.  If not, see
16
 * <https://www.gnu.org/licenses/>.
17
 */
18

19
using System;
20
using System.Collections.Generic;
21
using MongoDB.Bson;
22
using MongoDB.Bson.IO;
23

24
namespace AccountingServer.DAL.Serializer;
25

26
/// <summary>
27
///     Bson序列化辅助读写
28
/// </summary>
29
internal static class SerializationHelper
30
{
31
    /// <summary>
32
    ///     安全地判断是否读到文档结尾
33
    /// </summary>
34
    /// <param name="bsonReader">Bson读取器</param>
35
    /// <returns>是否读到文档结尾</returns>
36
    private static bool IsEndOfDocument(this IBsonReader bsonReader)
37
    {
8,243✔
38
        if (bsonReader.State == BsonReaderState.Type)
8,243✔
39
            bsonReader.ReadBsonType();
5,968✔
40
        return bsonReader.State == BsonReaderState.EndOfDocument;
8,243✔
41
    }
8,243✔
42

43
    /// <summary>
44
    ///     安全地判断是否读到数组结尾
45
    /// </summary>
46
    /// <param name="bsonReader">Bson读取器</param>
47
    /// <returns>是否读到数组结尾</returns>
48
    private static bool IsEndOfArray(this IBsonReader bsonReader)
49
    {
974✔
50
        if (bsonReader.State == BsonReaderState.Type)
974✔
51
            bsonReader.ReadBsonType();
974✔
52
        return bsonReader.State == BsonReaderState.EndOfArray;
974✔
53
    }
974✔
54

55
    /// <summary>
56
    ///     安全地读入指定字段的名称
57
    /// </summary>
58
    /// <param name="bsonReader">Bson读取器</param>
59
    /// <param name="expected">字段名</param>
60
    /// <param name="read">字段名缓存</param>
61
    /// <returns>是否可以继续读入</returns>
62
    private static bool ReadName(this IBsonReader bsonReader, string expected, ref string read)
63
    {
8,243✔
64
        if (bsonReader.IsEndOfDocument())
8,243✔
65
            return false;
1,071✔
66

67
        read ??= bsonReader.ReadName();
7,172✔
68
        if (read != expected)
7,172✔
69
            return false;
1,629✔
70

71
        read = null;
5,543✔
72
        return true;
5,543✔
73
    }
8,243✔
74

75
    /// <summary>
76
    ///     做安全读入指定字段之前的准备工作
77
    /// </summary>
78
    /// <param name="bsonReader">Bson读取器</param>
79
    /// <param name="expected">字段名</param>
80
    /// <param name="read">字段名缓存</param>
81
    /// <returns>是否可以继续读入</returns>
82
    private static bool ReadPrep(this IBsonReader bsonReader, string expected, ref string read)
83
    {
8,217✔
84
        if (!bsonReader.ReadName(expected, ref read))
8,217✔
85
            return false;
2,700✔
86

87
        switch (bsonReader.CurrentBsonType)
5,517✔
88
        {
89
            case BsonType.Null:
90
                bsonReader.ReadNull();
×
91
                return false;
×
92
            case BsonType.Undefined:
93
                bsonReader.ReadUndefined();
×
94
                return false;
×
95
        }
96

97
        return true;
5,517✔
98
    }
8,217✔
99

100
    /// <summary>
101
    ///     安全地读入指定引用类型的字段
102
    /// </summary>
103
    /// <param name="bsonReader">Bson读取器</param>
104
    /// <param name="expected">字段名</param>
105
    /// <param name="read">字段名缓存</param>
106
    /// <param name="readFunc">类型读取器</param>
107
    /// <returns>读取结果</returns>
108
    private static T ReadClass<T>(this IBsonReader bsonReader, string expected, ref string read,
109
        Func<T> readFunc) where T : class
110
        => ReadPrep(bsonReader, expected, ref read) ? readFunc() : null;
4,293✔
111

112
    /// <summary>
113
    ///     安全地读入指定值类型的字段
114
    /// </summary>
115
    /// <param name="bsonReader">Bson读取器</param>
116
    /// <param name="expected">字段名</param>
117
    /// <param name="read">字段名缓存</param>
118
    /// <param name="readFunc">类型读取器</param>
119
    /// <returns>读取结果</returns>
120
    private static T? ReadStruct<T>(this IBsonReader bsonReader, string expected, ref string read,
121
        Func<T> readFunc) where T : struct
122
        => ReadPrep(bsonReader, expected, ref read) ? readFunc() : null;
3,507✔
123

124
    /// <summary>
125
    ///     安全地读入<c>ObjectId</c>类型的字段
126
    /// </summary>
127
    /// <param name="bsonReader">Bson读取器</param>
128
    /// <param name="expected">字段名</param>
129
    /// <param name="read">字段名缓存</param>
130
    /// <returns>读取结果</returns>
131
    public static string ReadObjectId(this IBsonReader bsonReader, string expected, ref string read)
132
        => ReadClass(bsonReader, expected, ref read, () => bsonReader.ReadObjectId().ToString());
147✔
133

134
    /// <summary>
135
    ///     安全地读入<c>Int32</c>类型的字段
136
    /// </summary>
137
    /// <param name="bsonReader">Bson读取器</param>
138
    /// <param name="expected">字段名</param>
139
    /// <param name="read">字段名缓存</param>
140
    /// <returns>读取结果</returns>
141
    public static int? ReadInt32(this IBsonReader bsonReader, string expected, ref string read)
142
        => ReadStruct(bsonReader, expected, ref read, bsonReader.ReadInt32);
1,645✔
143

144
    /// <summary>
145
    ///     安全地读入<c>UInt32</c>类型的字段
146
    /// </summary>
147
    /// <param name="bsonReader">Bson读取器</param>
148
    /// <param name="expected">字段名</param>
149
    /// <param name="read">字段名缓存</param>
150
    /// <returns>读取结果</returns>
151
    public static uint? ReadUInt32(this IBsonReader bsonReader, string expected, ref string read)
152
        => ReadStruct(bsonReader, expected, ref read, () => (uint)bsonReader.ReadInt64());
×
153

154
    /// <summary>
155
    ///     安全地读入<c>Double</c>类型的字段
156
    /// </summary>
157
    /// <param name="bsonReader">Bson读取器</param>
158
    /// <param name="expected">字段名</param>
159
    /// <param name="read">字段名缓存</param>
160
    /// <returns>读取结果</returns>
161
    public static double? ReadDouble(this IBsonReader bsonReader, string expected, ref string read)
162
        => ReadStruct(bsonReader, expected, ref read, bsonReader.ReadDouble);
1,239✔
163

164
    /// <summary>
165
    ///     安全地读入<c>string</c>类型的字段
166
    /// </summary>
167
    /// <param name="bsonReader">Bson读取器</param>
168
    /// <param name="expected">字段名</param>
169
    /// <param name="read">字段名缓存</param>
170
    /// <returns>读取结果</returns>
171
    public static string ReadString(this IBsonReader bsonReader, string expected, ref string read)
172
        => ReadClass(bsonReader, expected, ref read, bsonReader.ReadString);
3,928✔
173

174
    /// <summary>
175
    ///     安全地读入<c>Guid</c>类型的字段
176
    /// </summary>
177
    /// <param name="bsonReader">Bson读取器</param>
178
    /// <param name="expected">字段名</param>
179
    /// <param name="read">字段名缓存</param>
180
    /// <returns>读取结果</returns>
181
    public static Guid? ReadGuid(this IBsonReader bsonReader, string expected, ref string read)
182
        => ReadStruct(bsonReader, expected, ref read, () => {
64✔
183
                var d = bsonReader.ReadBinaryData();
64✔
184
                if (d.SubType == BsonBinarySubType.UuidLegacy)
64✔
185
                    return d.ToGuid(GuidRepresentation.CSharpLegacy);
×
186

187
                return d.ToGuid(GuidRepresentation.Standard);
64✔
188
            });
64✔
189

190
    /// <summary>
191
    ///     安全地读入<c>DateTime</c>类型的字段
192
    /// </summary>
193
    /// <param name="bsonReader">Bson读取器</param>
194
    /// <param name="expected">字段名</param>
195
    /// <param name="read">字段名缓存</param>
196
    /// <returns>读取结果</returns>
197
    public static DateTime? ReadDateTime(this IBsonReader bsonReader, string expected, ref string read)
198
        => ReadStruct(
559✔
199
            bsonReader,
200
            expected,
201
            ref read,
202
            () =>
203
                BsonUtils.ToDateTimeFromMillisecondsSinceEpoch(bsonReader.ReadDateTime()).ToUniversalTime());
302✔
204

205
    /// <summary>
206
    ///     安全地读入<c>BinData</c>类型的字段
207
    /// </summary>
208
    /// <param name="bsonReader">Bson读取器</param>
209
    /// <param name="expected">字段名</param>
210
    /// <param name="read">字段名缓存</param>
211
    /// <returns>读取结果</returns>
212
    public static byte[] ReadBinaryData(this IBsonReader bsonReader, string expected, ref string read)
213
        => ReadClass(bsonReader, expected, ref read, () => bsonReader.ReadBinaryData().AsByteArray);
×
214

215
    /// <summary>
216
    ///     安全地读入<c>bool</c>类型的字段
217
    /// </summary>
218
    /// <param name="bsonReader">Bson读取器</param>
219
    /// <param name="expected">字段名</param>
220
    /// <param name="read">字段名缓存</param>
221
    /// <returns>读取结果</returns>
222
    public static bool ReadBoolean(this IBsonReader bsonReader, string expected, ref string read)
223
        => ReadStruct(bsonReader, expected, ref read, () => bsonReader.ReadBoolean()) == true;
×
224

225
    /// <summary>
226
    ///     安全地读入<c>null</c>类型的字段
227
    /// </summary>
228
    /// <param name="bsonReader">Bson读取器</param>
229
    /// <param name="expected">字段名</param>
230
    /// <param name="read">字段名缓存</param>
231
    /// <returns>是否成功</returns>
232
    public static bool ReadNull(this IBsonReader bsonReader, string expected, ref string read)
233
    {
26✔
234
        if (!bsonReader.ReadName(expected, ref read))
26✔
235
            return false;
×
236

237
        bsonReader.ReadNull();
26✔
238
        return true;
26✔
239
    }
26✔
240

241
    /// <summary>
242
    ///     安全地读入文档字段
243
    /// </summary>
244
    /// <param name="bsonReader">Bson读取器</param>
245
    /// <param name="expected">字段名</param>
246
    /// <param name="read">字段名缓存</param>
247
    /// <param name="parser">文档读取器</param>
248
    /// <returns>读取结果</returns>
249
    public static T ReadDocument<T>(this IBsonReader bsonReader, string expected, ref string read,
250
        Func<IBsonReader, T> parser)
251
        => ReadPrep(bsonReader, expected, ref read) ? parser(bsonReader) : default;
168✔
252

253
    /// <summary>
254
    ///     安全地读入数组字段
255
    /// </summary>
256
    /// <param name="bsonReader">Bson读取器</param>
257
    /// <param name="expected">字段名</param>
258
    /// <param name="read">字段名缓存</param>
259
    /// <param name="parser">数组元素读取器</param>
260
    /// <returns>读取结果</returns>
261
    public static List<T> ReadArray<T>(this IBsonReader bsonReader, string expected, ref string read,
262
        Func<IBsonReader, T> parser)
263
    {
249✔
264
        if (!ReadPrep(bsonReader, expected, ref read))
249✔
265
            return null;
×
266

267
        var lst = new List<T>();
249✔
268
        bsonReader.ReadStartArray();
249✔
269
        while (!bsonReader.IsEndOfArray())
974✔
270
            lst.Add(parser(bsonReader));
725✔
271

272
        bsonReader.ReadEndArray();
249✔
273
        return lst;
249✔
274
    }
249✔
275

276
    /// <summary>
277
    ///     安全地写入<c>ObjectId</c>类型的字段
278
    /// </summary>
279
    /// <param name="bsonWriter">Bson读取器</param>
280
    /// <param name="name">字段名</param>
281
    /// <param name="value">字段值</param>
282
    /// <param name="force">是否强制写入<c>null</c>值</param>
283
    public static void WriteObjectId(this IBsonWriter bsonWriter, string name, string value, bool force = false)
284
    {
702✔
285
        if (value != null)
702✔
286
            bsonWriter.WriteObjectId(name, ObjectId.Parse(value));
442✔
287
        else if (force)
260✔
288
            bsonWriter.WriteNull(name);
×
289
    }
702✔
290

291
    /// <summary>
292
    ///     安全地写入<c>byte[]</c>类型的字段
293
    /// </summary>
294
    /// <param name="bsonWriter">Bson读取器</param>
295
    /// <param name="name">字段名</param>
296
    /// <param name="value">字段值</param>
297
    /// <param name="force">是否强制写入<c>null</c>值</param>
298
    public static void Write(this IBsonWriter bsonWriter, string name, byte[] value, bool force = false)
299
    {
×
300
        if (value != null)
×
301
            bsonWriter.WriteBinaryData(name, value);
×
302
        else if (force)
×
303
            bsonWriter.WriteNull(name);
×
304
    }
×
305

306
    /// <summary>
307
    ///     安全地写入<c>Guid</c>类型的字段
308
    /// </summary>
309
    /// <param name="bsonWriter">Bson读取器</param>
310
    /// <param name="name">字段名</param>
311
    /// <param name="value">字段值</param>
312
    /// <param name="force">是否强制写入<c>null</c>值</param>
313
    public static void Write(this IBsonWriter bsonWriter, string name, Guid? value, bool force = false)
314
    {
76✔
315
        if (value.HasValue)
76✔
316
            bsonWriter.WriteBinaryData(name, value.Value.ToBsonValue());
76✔
317
        else if (force)
×
318
            bsonWriter.WriteNull(name);
×
319
    }
76✔
320

321
    /// <summary>
322
    ///     安全地写入<c>int</c>类型的字段
323
    /// </summary>
324
    /// <param name="bsonWriter">Bson读取器</param>
325
    /// <param name="name">字段名</param>
326
    /// <param name="value">字段值</param>
327
    /// <param name="force">是否强制写入<c>null</c>值</param>
328
    public static void Write(this IBsonWriter bsonWriter, string name, int? value, bool force = false)
329
    {
3,534✔
330
        if (value.HasValue)
3,534✔
331
            bsonWriter.WriteInt32(name, value.Value);
3,002✔
332
        else if (force)
532✔
333
            bsonWriter.WriteNull(name);
×
334
    }
3,534✔
335

336
    /// <summary>
337
    ///     安全地写入<c>uint</c>类型的字段
338
    /// </summary>
339
    /// <param name="bsonWriter">Bson读取器</param>
340
    /// <param name="name">字段名</param>
341
    /// <param name="value">字段值</param>
342
    /// <param name="force">是否强制写入<c>null</c>值</param>
343
    public static void Write(this IBsonWriter bsonWriter, string name, uint? value, bool force = false)
344
    {
×
345
        if (value.HasValue)
×
346
            bsonWriter.WriteInt64(name, value.Value);
×
347
        else if (force)
×
348
            bsonWriter.WriteNull(name);
×
349
    }
×
350

351
    /// <summary>
352
    ///     安全地写入<c>double</c>类型的字段
353
    /// </summary>
354
    /// <param name="bsonWriter">Bson读取器</param>
355
    /// <param name="name">字段名</param>
356
    /// <param name="value">字段值</param>
357
    /// <param name="force">是否强制写入<c>null</c>值</param>
358
    public static void Write(this IBsonWriter bsonWriter, string name, double? value, bool force = false)
359
    {
1,941✔
360
        if (value.HasValue)
1,941✔
361
            bsonWriter.WriteDouble(name, value.Value);
1,941✔
362
        else if (force)
×
363
            bsonWriter.WriteNull(name);
×
364
    }
1,941✔
365

366
    /// <summary>
367
    ///     安全地写入<c>DateTime</c>类型的字段
368
    /// </summary>
369
    /// <param name="bsonWriter">Bson读取器</param>
370
    /// <param name="name">字段名</param>
371
    /// <param name="value">字段值</param>
372
    /// <param name="force">是否强制写入<c>null</c>值</param>
373
    public static void Write(this IBsonWriter bsonWriter, string name, DateTime? value, bool force = false)
374
    {
778✔
375
        if (value.HasValue)
778✔
376
            bsonWriter.WriteDateTime(name, BsonUtils.ToMillisecondsSinceEpoch(value.Value));
597✔
377
        else if (force)
181✔
378
            bsonWriter.WriteNull(name);
×
379
    }
778✔
380

381
    /// <summary>
382
    ///     安全地写入<c>string</c>类型的字段
383
    /// </summary>
384
    /// <param name="bsonWriter">Bson读取器</param>
385
    /// <param name="name">字段名</param>
386
    /// <param name="value">字段值</param>
387
    /// <param name="force">是否强制写入<c>null</c>值</param>
388
    public static void Write(this IBsonWriter bsonWriter, string name, string value, bool force = false)
389
    {
4,040✔
390
        if (value != null)
4,040✔
391
            bsonWriter.WriteString(name, value);
2,994✔
392
        else if (force)
1,046✔
393
            bsonWriter.WriteNull(name);
×
394
    }
4,040✔
395

396
    /// <summary>
397
    ///     安全地写入<c>bool</c>类型的字段
398
    /// </summary>
399
    /// <param name="bsonWriter">Bson读取器</param>
400
    /// <param name="name">字段名</param>
401
    /// <param name="value">字段值</param>
402
    /// <param name="force">是否强制写入<c>false</c>值</param>
403
    public static void Write(this IBsonWriter bsonWriter, string name, bool value, bool force = false)
404
    {
×
405
        if (value || force)
×
406
            bsonWriter.WriteBoolean(name, value);
×
407
    }
×
408

409
    /// <summary>
410
    ///     将<c>Guid</c>转换为Bson对象
411
    /// </summary>
412
    /// <param name="id">
413
    ///     <c>Guid</c>
414
    /// </param>
415
    /// <returns>Bson对象</returns>
416
    public static BsonBinaryData ToBsonValue(this Guid id) => new(id, GuidRepresentation.Standard);
142✔
417
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc