3using MongoDB.Bson.Serialization;
8using System.Reflection;
9using System.Runtime.ExceptionServices;
10using System.Threading;
11using System.Threading.Tasks;
32 private readonly Dictionary<string, IMongoCollection<BsonDocument>> collections = [];
33 private readonly Dictionary<Type, IObjectSerializer> serializers = [];
34 private readonly AutoResetEvent serializerAdded =
new(
false);
35 private MongoClient client;
36 private IMongoDatabase database;
38 private string defaultCollectionName;
39 private string lastCollectionName =
null;
40 private IMongoCollection<BsonDocument> lastCollection =
null;
41 private IMongoCollection<BsonDocument> defaultCollection;
50 MongoClientSettings Settings =
new();
62 MongoClientSettings Settings =
new()
64 Server =
new MongoServerAddress(HostName)
79 MongoClientSettings Settings =
new()
81 Server =
new MongoServerAddress(HostName, Port)
100 this.id = Guid.NewGuid().ToString().Replace(
"-",
string.Empty);
101 this.client =
new MongoClient(Settings);
102 this.database = this.client.GetDatabase(DatabaseName);
105 this.defaultCollection = this.
GetCollection(this.defaultCollectionName);
107 ConstructorInfo DefaultConstructor;
115 if (DefaultConstructor is
null)
137 public string Id => this.id;
151 IMongoCollection<BsonDocument> Result;
153 lock (this.collections)
155 if (CollectionName == this.lastCollectionName)
156 Result = this.lastCollection;
159 if (!this.collections.TryGetValue(CollectionName, out Result))
161 Result = this.database.GetCollection<BsonDocument>(CollectionName);
162 this.collections[CollectionName] = Result;
165 this.lastCollection = Result;
166 this.lastCollectionName = CollectionName;
176 public MongoClient
Client => this.client;
196 TypeInfo TI = Type.GetTypeInfo();
198 lock (this.collections)
200 if (this.serializers.TryGetValue(Type, out Result))
205 else if (Type.IsArray)
207 Type ElementType = Type.GetElementType();
209 Type SerializerType = T.MakeGenericType([ElementType]);
212 else if (TI.IsGenericType)
214 Type GT = Type.GetGenericTypeDefinition();
215 if (GT == typeof(Nullable<>))
217 Type NullableType = Type.GenericTypeArguments[0];
219 if (NullableType.IsEnum)
220 Result =
new Serialization.NullableTypes.NullableEnumSerializer(NullableType);
230 if (Result is not
null)
232 this.serializers[Type] = Result;
233 this.serializerAdded.Set();
243 lock (this.collections)
245 this.serializers[Type] = Result;
246 this.serializerAdded.Set();
249 catch (FileLoadException ex)
255 if (!this.serializerAdded.WaitOne(1000))
256 ExceptionDispatchInfo.Capture(ex).Throw();
258 lock (this.collections)
260 if (this.serializers.TryGetValue(Type, out Result))
287 throw new Exception(
"Objects of type " + Type.FullName +
" must be embedded.");
300 IMongoCollection<BsonDocument> Collection;
302 if (
string.IsNullOrEmpty(CollectionName))
303 Collection = this.defaultCollection;
310 throw new Exception(
"Object already has an Object ID. If updating an object, use the Update method.");
316 BsonDocument Doc = Object.ToBsonDocument(Object.GetType(), Serializer);
317 await Collection.InsertOneAsync(Doc);
325 public Task
Insert(params
object[] Objects)
327 return this.
Insert((IEnumerable<object>)Objects);
334 public async Task
Insert(IEnumerable<object> Objects)
336 Dictionary<string, KeyValuePair<IMongoCollection<BsonDocument>, LinkedList<BsonDocument>>> DocumentsPerCollection = [];
338 Type LastType =
null;
340 string CollectionName;
341 string LastCollectionName =
null;
342 IMongoCollection<BsonDocument> Collection;
343 IMongoCollection<BsonDocument> LastCollection =
null;
344 LinkedList<BsonDocument> Documents =
null;
345 BsonDocument Document;
347 foreach (
object Object
in Objects)
349 Type = Object.GetType();
351 if (Type != LastType)
354 CollectionName = Serializer.CollectionName(Object);
357 if (CollectionName == LastCollectionName)
358 Collection = LastCollection;
361 LastCollectionName = CollectionName;
363 if (
string.IsNullOrEmpty(CollectionName))
364 CollectionName = this.defaultCollectionName;
366 if (DocumentsPerCollection.TryGetValue(CollectionName, out KeyValuePair<IMongoCollection<BsonDocument>, LinkedList<BsonDocument>> P))
371 P =
new KeyValuePair<IMongoCollection<BsonDocument>, LinkedList<BsonDocument>>(Collection,
new LinkedList<BsonDocument>());
372 DocumentsPerCollection[CollectionName] = P;
376 LastCollection = Collection;
380 Document = Object.ToBsonDocument(Type, Serializer);
381 Documents.AddLast(Document);
384 foreach (KeyValuePair<IMongoCollection<BsonDocument>, LinkedList<BsonDocument>> P2
in DocumentsPerCollection.Values)
385 await P2.Key.InsertManyAsync(P2.Value);
421 public Task<IEnumerable<T>>
Find<T>(
int Offset,
int MaxCount, params
string[] SortOrder)
424 return this.
Find<T>(Offset, MaxCount, (
Filter)
null, SortOrder);
442 IMongoCollection<BsonDocument> Collection;
443 FilterDefinition<BsonDocument> BsonFilter;
445 if (
string.IsNullOrEmpty(CollectionName))
446 Collection = this.defaultCollection;
451 BsonFilter =
new BsonDocument();
453 BsonFilter = Convert(
Filter, Serializer);
455 return Find<T>(Serializer, Collection, Offset, MaxCount, BsonFilter,
null, SortOrder);
470 T ContinueAfter, params
string[] SortOrder)
475 IMongoCollection<BsonDocument> Collection;
476 FilterDefinition<BsonDocument> BsonFilter;
478 if (
string.IsNullOrEmpty(CollectionName))
479 Collection = this.defaultCollection;
484 BsonFilter =
new BsonDocument();
486 BsonFilter = Convert(
Filter, Serializer);
488 return Find(Serializer, Collection, Offset, MaxCount, BsonFilter, ContinueAfter, SortOrder);
501 public Task<IEnumerable<T>>
Find<T>(
int Offset,
int MaxCount, FilterDefinition<BsonDocument> BsonFilter,
502 params
string[] SortOrder)
507 IMongoCollection<BsonDocument> Collection;
509 if (
string.IsNullOrEmpty(CollectionName))
510 Collection = this.defaultCollection;
514 return Find<T>(Serializer, Collection, Offset, MaxCount, BsonFilter,
null, SortOrder);
527 public Task<IEnumerable<T>>
Find<T>(
string CollectionName,
int Offset,
int MaxCount,
Filter Filter, params
string[] SortOrder)
531 IMongoCollection<BsonDocument> Collection;
532 FilterDefinition<BsonDocument> BsonFilter;
534 if (
string.IsNullOrEmpty(CollectionName))
535 Collection = this.defaultCollection;
540 BsonFilter =
new BsonDocument();
542 BsonFilter = Convert(
Filter, Serializer);
544 return Find<T>(Serializer, Collection, Offset, MaxCount, BsonFilter,
null, SortOrder);
559 T ContinueAfter, params
string[] SortOrder)
563 IMongoCollection<BsonDocument> Collection;
564 FilterDefinition<BsonDocument> BsonFilter;
566 if (
string.IsNullOrEmpty(CollectionName))
567 Collection = this.defaultCollection;
572 BsonFilter =
new BsonDocument();
574 BsonFilter = Convert(
Filter, Serializer);
576 return Find(Serializer, Collection, Offset, MaxCount, BsonFilter, ContinueAfter, SortOrder);
588 public Task<IEnumerable<object>>
Find(
string CollectionName,
int Offset,
int MaxCount, params
string[] SortOrder)
590 return this.
Find(CollectionName, Offset, MaxCount,
null, SortOrder);
603 public Task<IEnumerable<object>>
Find(
string CollectionName,
int Offset,
int MaxCount,
Filter Filter, params
string[] SortOrder)
606 IMongoCollection<BsonDocument> Collection;
607 FilterDefinition<BsonDocument> BsonFilter;
609 if (
string.IsNullOrEmpty(CollectionName))
610 Collection = this.defaultCollection;
615 BsonFilter =
new BsonDocument();
617 BsonFilter = Convert(
Filter, Serializer);
619 return Find<object>(Serializer, Collection, Offset, MaxCount, BsonFilter, SortOrder);
622 private static async Task<IEnumerable<T>>
Find<T>(
ObjectSerializer Serializer, IMongoCollection<BsonDocument> Collection,
623 int Offset,
int MaxCount, FilterDefinition<BsonDocument> BsonFilter, T ContinueAfter, params
string[] SortOrder)
626 if (ContinueAfter is not
null)
627 throw new NotImplementedException(
"Paginated searches not implemented in MongoDB provider.");
629 IFindFluent<BsonDocument, BsonDocument> ResultSet = Collection.Find(BsonFilter);
631 if (SortOrder.Length > 0)
633 SortDefinition<BsonDocument> SortDefinition =
null;
635 foreach (
string SortBy
in SortOrder)
637 if (SortDefinition is
null)
639 if (SortBy.StartsWith(
'-'))
640 SortDefinition = Builders<BsonDocument>.Sort.Descending(Serializer.ToShortName(SortBy[1..]));
642 SortDefinition = Builders<BsonDocument>.Sort.Ascending(Serializer.ToShortName(SortBy));
646 if (SortBy.StartsWith(
'-'))
647 SortDefinition = SortDefinition.Descending(Serializer.ToShortName(SortBy[1..]));
649 SortDefinition = SortDefinition.Ascending(Serializer.ToShortName(SortBy));
653 ResultSet = ResultSet.Sort(SortDefinition);
657 ResultSet = ResultSet.Skip(Offset);
659 if (MaxCount <
int.MaxValue)
660 ResultSet = ResultSet.Limit(MaxCount);
662 IAsyncCursor<BsonDocument> Cursor = await ResultSet.ToCursorAsync();
663 LinkedList<T> Result =
new();
664 BsonDeserializationArgs Args =
new()
666 NominalType = typeof(T)
669 while (await Cursor.MoveNextAsync())
671 foreach (BsonDocument Document
in Cursor.Current)
673 BsonDocumentReader Reader =
new(Document);
674 BsonDeserializationContext Context = BsonDeserializationContext.CreateRoot(Reader);
676 if (Serializer.Deserialize(Context, Args) is T Obj)
689 int i, c = ChildFilters.Length;
690 FilterDefinition<BsonDocument>[] Children =
new FilterDefinition<BsonDocument>[c];
692 for (i = 0; i < c; i++)
693 Children[i] = Convert(ChildFilters[i], Serializer);
696 return Builders<BsonDocument>.Filter.And(Children);
698 return Builders<BsonDocument>.Filter.Or(Children);
700 throw UnknownFilterType(
Filter);
707 return Builders<BsonDocument>.Filter.Not(Child);
709 throw UnknownFilterType(
Filter);
721 return Builders<BsonDocument>.Filter.Eq<
string>(FieldName,
null);
722 else if (Value is
string s)
725 return Builders<BsonDocument>.
Filter.Eq<
string>(FieldName +
"_L", s);
727 return Builders<BsonDocument>.
Filter.Eq<
string>(FieldName, s);
730 return Builders<BsonDocument>.Filter.Eq<
string>(FieldName +
"_L", cis.LowerCase);
731 else if (Value is sbyte i8)
732 return Builders<BsonDocument>.Filter.Eq<
int>(FieldName, i8);
733 else if (Value is
short i16)
734 return Builders<BsonDocument>.Filter.Eq<
int>(FieldName, i16);
735 else if (Value is
int i32)
736 return Builders<BsonDocument>.Filter.Eq<
int>(FieldName, i32);
737 else if (Value is
long i64)
738 return Builders<BsonDocument>.Filter.Eq<
long>(FieldName, i64);
739 else if (Value is
byte ui8)
740 return Builders<BsonDocument>.Filter.Eq<
int>(FieldName, ui8);
741 else if (Value is ushort ui16)
742 return Builders<BsonDocument>.Filter.Eq<
int>(FieldName, ui16);
743 else if (Value is uint ui32)
744 return Builders<BsonDocument>.Filter.Eq<
long>(FieldName, ui32);
745 else if (Value is ulong ui64)
746 return Builders<BsonDocument>.Filter.Eq<Decimal128>(FieldName, ui64);
747 else if (Value is
double d)
748 return Builders<BsonDocument>.Filter.Eq<
double>(FieldName, d);
749 else if (Value is
float f)
750 return Builders<BsonDocument>.Filter.Eq<
double>(FieldName, f);
751 else if (Value is decimal d2)
752 return Builders<BsonDocument>.Filter.Eq<Decimal128>(FieldName, d2);
753 else if (Value is
bool b)
754 return Builders<BsonDocument>.Filter.Eq<
bool>(FieldName, b);
755 else if (Value is DateTime DT)
757 else if (Value is DateTimeOffset DTO)
759 return Builders<BsonDocument>.Filter.And(
761 Builders<BsonDocument>.
Filter.Eq<
string>(FieldName +
".tz", DTO.Offset.ToString()));
763 else if (Value is TimeSpan TS)
764 return Builders<BsonDocument>.Filter.Eq<
string>(FieldName, TS.ToString());
765 else if (Value is Guid Guid)
766 return Builders<BsonDocument>.Filter.Eq<
string>(FieldName, Guid.ToString());
767 else if (Value is ObjectId ObjectId)
768 return Builders<BsonDocument>.Filter.Eq<ObjectId>(FieldName, ObjectId);
770 throw UnhandledFilterValueDataType(Serializer.
ValueType.FullName, FieldName, Value);
775 return Builders<BsonDocument>.Filter.Ne<
string>(FieldName,
null);
776 else if (Value is
string s)
779 return Builders<BsonDocument>.
Filter.Ne<
string>(FieldName +
"_L", s);
781 return Builders<BsonDocument>.
Filter.Ne<
string>(FieldName, s);
784 return Builders<BsonDocument>.Filter.Ne<
string>(FieldName +
"_L", cis.LowerCase);
785 else if (Value is sbyte i8)
786 return Builders<BsonDocument>.Filter.Ne<
int>(FieldName, i8);
787 else if (Value is
short i16)
788 return Builders<BsonDocument>.Filter.Ne<
int>(FieldName, i16);
789 else if (Value is
int i32)
790 return Builders<BsonDocument>.Filter.Ne<
int>(FieldName, i32);
791 else if (Value is
long i64)
792 return Builders<BsonDocument>.Filter.Ne<
long>(FieldName, i64);
793 else if (Value is
byte ui8)
794 return Builders<BsonDocument>.Filter.Ne<
int>(FieldName, ui8);
795 else if (Value is ushort ui16)
796 return Builders<BsonDocument>.Filter.Ne<
int>(FieldName, ui16);
797 else if (Value is uint ui32)
798 return Builders<BsonDocument>.Filter.Ne<
long>(FieldName, ui32);
799 else if (Value is ulong ui64)
800 return Builders<BsonDocument>.Filter.Ne<Decimal128>(FieldName, ui64);
801 else if (Value is
double d)
802 return Builders<BsonDocument>.Filter.Ne<
double>(FieldName, d);
803 else if (Value is
float f)
804 return Builders<BsonDocument>.Filter.Ne<
double>(FieldName, f);
805 else if (Value is decimal d2)
806 return Builders<BsonDocument>.Filter.Ne<Decimal128>(FieldName, d2);
807 else if (Value is
bool b)
808 return Builders<BsonDocument>.Filter.Ne<
bool>(FieldName, b);
809 else if (Value is DateTime DT)
811 else if (Value is DateTimeOffset DTO)
813 return Builders<BsonDocument>.Filter.Or(
815 Builders<BsonDocument>.
Filter.Ne<
string>(FieldName +
".tz", DTO.Offset.ToString()));
817 else if (Value is TimeSpan TS)
818 return Builders<BsonDocument>.Filter.Ne<
string>(FieldName, TS.ToString());
819 else if (Value is Guid Guid)
820 return Builders<BsonDocument>.Filter.Ne<
string>(FieldName, Guid.ToString());
821 else if (Value is ObjectId ObjectId)
822 return Builders<BsonDocument>.Filter.Ne<ObjectId>(FieldName, ObjectId);
824 throw UnhandledFilterValueDataType(Serializer.
ValueType.FullName, FieldName, Value);
828 if (Value is
string s)
831 return Builders<BsonDocument>.Filter.Gt<
string>(FieldName +
"_L", s);
833 return Builders<BsonDocument>.Filter.Gt<
string>(FieldName, s);
836 return Builders<BsonDocument>.Filter.Gt<
string>(FieldName +
"_L", cis.LowerCase);
837 else if (Value is sbyte i8)
838 return Builders<BsonDocument>.Filter.Gt<
int>(FieldName, i8);
839 else if (Value is
short i16)
840 return Builders<BsonDocument>.Filter.Gt<
int>(FieldName, i16);
841 else if (Value is
int i32)
842 return Builders<BsonDocument>.Filter.Gt<
int>(FieldName, i32);
843 else if (Value is
long i64)
844 return Builders<BsonDocument>.Filter.Gt<
long>(FieldName, i64);
845 else if (Value is
byte ui8)
846 return Builders<BsonDocument>.Filter.Gt<
int>(FieldName, ui8);
847 else if (Value is ushort ui16)
848 return Builders<BsonDocument>.Filter.Gt<
int>(FieldName, ui16);
849 else if (Value is uint ui32)
850 return Builders<BsonDocument>.Filter.Gt<
long>(FieldName, ui32);
851 else if (Value is ulong ui64)
852 return Builders<BsonDocument>.Filter.Gt<Decimal128>(FieldName, ui64);
853 else if (Value is
double d)
854 return Builders<BsonDocument>.Filter.Gt<
double>(FieldName, d);
855 else if (Value is
float f)
856 return Builders<BsonDocument>.Filter.Gt<
double>(FieldName, f);
857 else if (Value is decimal d2)
858 return Builders<BsonDocument>.Filter.Gt<Decimal128>(FieldName, d2);
859 else if (Value is
bool b)
860 return Builders<BsonDocument>.Filter.Gt<
bool>(FieldName, b);
861 else if (Value is DateTime DT)
863 else if (Value is TimeSpan TS)
864 return Builders<BsonDocument>.Filter.Gt<
string>(FieldName, TS.ToString());
865 else if (Value is Guid Guid)
866 return Builders<BsonDocument>.Filter.Gt<
string>(FieldName, Guid.ToString());
867 else if (Value is ObjectId ObjectId)
868 return Builders<BsonDocument>.Filter.Gt<ObjectId>(FieldName, ObjectId);
870 throw UnhandledFilterValueDataType(Serializer.
ValueType.FullName, FieldName, Value);
879 else if (Value is
string s)
882 return Builders<BsonDocument>.Filter.Gte<
string>(FieldName +
"_L", s);
884 return Builders<BsonDocument>.Filter.Gte<
string>(FieldName, s);
887 return Builders<BsonDocument>.Filter.Gte<
string>(FieldName +
"_L", cis.LowerCase);
888 else if (Value is sbyte i8)
889 return Builders<BsonDocument>.Filter.Gte<
int>(FieldName, i8);
890 else if (Value is
short i16)
891 return Builders<BsonDocument>.Filter.Gte<
int>(FieldName, i16);
892 else if (Value is
int i32)
893 return Builders<BsonDocument>.Filter.Gte<
int>(FieldName, i32);
894 else if (Value is
long i64)
895 return Builders<BsonDocument>.Filter.Gte<
long>(FieldName, i64);
896 else if (Value is
byte ui8)
897 return Builders<BsonDocument>.Filter.Gte<
int>(FieldName, ui8);
898 else if (Value is ushort ui16)
899 return Builders<BsonDocument>.Filter.Gte<
int>(FieldName, ui16);
900 else if (Value is uint ui32)
901 return Builders<BsonDocument>.Filter.Gte<
long>(FieldName, ui32);
902 else if (Value is ulong ui64)
903 return Builders<BsonDocument>.Filter.Gte<Decimal128>(FieldName, ui64);
904 else if (Value is
double d)
905 return Builders<BsonDocument>.Filter.Gte<
double>(FieldName, d);
906 else if (Value is
float f)
907 return Builders<BsonDocument>.Filter.Gte<
double>(FieldName, f);
908 else if (Value is decimal d2)
909 return Builders<BsonDocument>.Filter.Gte<Decimal128>(FieldName, d2);
910 else if (Value is
bool b)
911 return Builders<BsonDocument>.Filter.Gte<
bool>(FieldName, b);
912 else if (Value is DateTime DT)
914 else if (Value is TimeSpan TS)
915 return Builders<BsonDocument>.Filter.Gte<
string>(FieldName, TS.ToString());
916 else if (Value is Guid Guid)
917 return Builders<BsonDocument>.Filter.Gte<
string>(FieldName, Guid.ToString());
918 else if (Value is ObjectId ObjectId)
919 return Builders<BsonDocument>.Filter.Gte<ObjectId>(FieldName, ObjectId);
921 throw UnhandledFilterValueDataType(Serializer.
ValueType.FullName, FieldName, Value);
925 if (Value is
string s)
928 return Builders<BsonDocument>.Filter.Lt<
string>(FieldName +
"_L", s);
930 return Builders<BsonDocument>.Filter.Lt<
string>(FieldName, s);
933 return Builders<BsonDocument>.Filter.Lt<
string>(FieldName +
"_L", cis.LowerCase);
934 else if (Value is sbyte i8)
935 return Builders<BsonDocument>.Filter.Lt<
int>(FieldName, i8);
936 else if (Value is
short i16)
937 return Builders<BsonDocument>.Filter.Lt<
int>(FieldName, i16);
938 else if (Value is
int i32)
939 return Builders<BsonDocument>.Filter.Lt<
int>(FieldName, i32);
940 else if (Value is
long i64)
941 return Builders<BsonDocument>.Filter.Lt<
long>(FieldName, i64);
942 else if (Value is
byte ui8)
943 return Builders<BsonDocument>.Filter.Lt<
int>(FieldName, ui8);
944 else if (Value is ushort ui16)
945 return Builders<BsonDocument>.Filter.Lt<
int>(FieldName, ui16);
946 else if (Value is uint ui32)
947 return Builders<BsonDocument>.Filter.Lt<
long>(FieldName, ui32);
948 else if (Value is ulong ui64)
949 return Builders<BsonDocument>.Filter.Lt<Decimal128>(FieldName, ui64);
950 else if (Value is
double d)
951 return Builders<BsonDocument>.Filter.Lt<
double>(FieldName, d);
952 else if (Value is
float f)
953 return Builders<BsonDocument>.Filter.Lt<
double>(FieldName, f);
954 else if (Value is decimal d2)
955 return Builders<BsonDocument>.Filter.Lt<Decimal128>(FieldName, d2);
956 else if (Value is
bool b)
957 return Builders<BsonDocument>.Filter.Lt<
bool>(FieldName, b);
958 else if (Value is DateTime DT)
960 else if (Value is TimeSpan TS)
961 return Builders<BsonDocument>.Filter.Lt<
string>(FieldName, TS.ToString());
962 else if (Value is Guid Guid)
963 return Builders<BsonDocument>.Filter.Lt<
string>(FieldName, Guid.ToString());
964 else if (Value is ObjectId ObjectId)
965 return Builders<BsonDocument>.Filter.Lt<ObjectId>(FieldName, ObjectId);
967 throw UnhandledFilterValueDataType(Serializer.
ValueType.FullName, FieldName, Value);
976 else if (Value is
string s)
979 return Builders<BsonDocument>.Filter.Lte<
string>(FieldName +
"_L", s);
981 return Builders<BsonDocument>.Filter.Lte<
string>(FieldName, s);
984 return Builders<BsonDocument>.Filter.Lte<
string>(FieldName +
"_L", cis.LowerCase);
985 else if (Value is sbyte i8)
986 return Builders<BsonDocument>.Filter.Lte<
int>(FieldName, i8);
987 else if (Value is
short i16)
988 return Builders<BsonDocument>.Filter.Lte<
int>(FieldName, i16);
989 else if (Value is
int i32)
990 return Builders<BsonDocument>.Filter.Lte<
int>(FieldName, i32);
991 else if (Value is
long i64)
992 return Builders<BsonDocument>.Filter.Lte<
long>(FieldName, i64);
993 else if (Value is
byte ui8)
994 return Builders<BsonDocument>.Filter.Lte<
int>(FieldName, ui8);
995 else if (Value is ushort ui16)
996 return Builders<BsonDocument>.Filter.Lte<
int>(FieldName, ui16);
997 else if (Value is uint ui32)
998 return Builders<BsonDocument>.Filter.Lte<
long>(FieldName, ui32);
999 else if (Value is ulong ui64)
1000 return Builders<BsonDocument>.Filter.Lte<Decimal128>(FieldName, ui64);
1001 else if (Value is
double d)
1002 return Builders<BsonDocument>.Filter.Lte<
double>(FieldName, d);
1003 else if (Value is
float f)
1004 return Builders<BsonDocument>.Filter.Lte<
double>(FieldName, f);
1005 else if (Value is decimal d2)
1006 return Builders<BsonDocument>.Filter.Lte<Decimal128>(FieldName, d2);
1007 else if (Value is
bool b)
1008 return Builders<BsonDocument>.Filter.Lte<
bool>(FieldName, b);
1009 else if (Value is DateTime DT)
1011 else if (Value is TimeSpan TS)
1012 return Builders<BsonDocument>.Filter.Lte<
string>(FieldName, TS.ToString());
1013 else if (Value is Guid Guid)
1014 return Builders<BsonDocument>.Filter.Lte<
string>(FieldName, Guid.ToString());
1015 else if (Value is ObjectId ObjectId)
1016 return Builders<BsonDocument>.Filter.Lte<ObjectId>(FieldName, ObjectId);
1018 throw UnhandledFilterValueDataType(Serializer.
ValueType.FullName, FieldName, Value);
1021 throw UnknownFilterType(
Filter);
1031 throw UnknownFilterType(
Filter);
1035 private static NotSupportedException UnknownFilterType(
Filter Filter)
1037 return new NotSupportedException(
"Filters of type " +
Filter.GetType().FullName +
" not supported.");
1040 private static NotSupportedException UnhandledFilterValueDataType(
string TypeName,
string FieldName,
object Value)
1044 return new NotSupportedException(
"Null filter values for field " + TypeName +
"." + FieldName +
1049 return new NotSupportedException(
"Filter values of type " + Value.GetType().FullName +
1050 " for field " + TypeName +
"." + FieldName +
" not supported.");
1062 public async Task<IPage<T>>
FindFirst<T>(
int PageSize, params
string[] SortOrder)
1066 IEnumerable<T> Items = await this.
Find<T>(0, PageSize, SortOrder);
1067 return new Page<T>(PageSize,
null,
null, SortOrder, Items, Serializer,
this);
1083 IEnumerable<T> Items = await this.
Find<T>(0, PageSize,
Filter, SortOrder);
1084 return new Page<T>(PageSize,
null,
Filter, SortOrder, Items, Serializer,
this);
1095 public async Task<IPage<object>>
FindFirst(
string Collection,
int PageSize, params
string[] SortOrder)
1098 IEnumerable<object> Items = await this.
Find(Collection, 0, PageSize, SortOrder);
1099 return new Page<object>(PageSize, Collection,
null, SortOrder, Items, Serializer,
this);
1114 IEnumerable<object> Items = await this.
Find(Collection, 0, PageSize,
Filter, SortOrder);
1115 return new Page<object>(PageSize, Collection,
Filter, SortOrder, Items, Serializer,
this);
1132 IEnumerable<T> Items = await this.
Find<T>(Collection, 0, PageSize,
Filter, SortOrder);
1133 return new Page<T>(PageSize, Collection,
Filter, SortOrder, Items, Serializer,
this);
1146 return CurrentPage.FindNext();
1148 throw new IOException(
"Incompatible page.");
1159 return CurrentPage.FindNext();
1161 throw new IOException(
"Incompatible page.");
1175 if (ObjectId is ObjectId ObjId)
1177 else if (ObjectId is
string s)
1178 OID =
new ObjectId(s);
1179 else if (ObjectId is
byte[] A)
1180 OID =
new ObjectId(A);
1181 else if (ObjectId is Guid Guid)
1184 throw new NotSupportedException(
"Unsupported type for Object ID: " + ObjectId.GetType().FullName);
1198 string Key = typeof(T).FullName +
" " + ObjectId.ToString();
1200 if (this.loadCache.
TryGetValue(Key, out
object Obj) && Obj is T Result)
1207 foreach (T Item
in ReferencedObjects)
1212 throw new Exception(
"Multiple objects of type T found with object ID " + ObjectId.ToString());
1215 if (First is not
null)
1216 this.loadCache.
Add(Key, First);
1233 if (ObjectId is ObjectId ObjId)
1235 else if (ObjectId is
string s)
1236 OID =
new ObjectId(s);
1237 else if (ObjectId is
byte[] A)
1238 OID =
new ObjectId(A);
1239 else if (ObjectId is Guid Guid)
1242 throw new NotSupportedException(
"Unsupported type for Object ID: " + ObjectId.GetType().FullName);
1257 string Key = typeof(T).FullName +
" " + ObjectId.ToString();
1259 if (this.loadCache.
TryGetValue(Key, out
object Obj) && Obj is T Result)
1266 foreach (T Item
in ReferencedObjects)
1271 throw new Exception(
"Multiple objects of type T found with object ID " + ObjectId.ToString());
1274 if (First is not
null)
1275 this.loadCache.
Add(Key, First);
1290 if (ObjectId is ObjectId ObjId)
1292 else if (ObjectId is
string s)
1293 OID =
new ObjectId(s);
1294 else if (ObjectId is
byte[] A)
1295 OID =
new ObjectId(A);
1296 else if (ObjectId is Guid Guid)
1299 throw new NotSupportedException(
"Unsupported type for Object ID: " + ObjectId.GetType().FullName);
1303 object First =
null;
1305 foreach (
object Item
in ReferencedObjects)
1310 throw new Exception(
"Multiple objects of type T found with object ID " + ObjectId.ToString());
1316 private readonly
Cache<string, object> loadCache =
new(10000,
new TimeSpan(0, 0, 10),
new TimeSpan(0, 0, 5),
true);
1332 return this.
Process<T>(Processor, Offset, MaxCount, (
Filter)
null, SortOrder);
1352 IMongoCollection<BsonDocument> Collection;
1353 FilterDefinition<BsonDocument> BsonFilter;
1355 if (
string.IsNullOrEmpty(CollectionName))
1356 Collection = this.defaultCollection;
1361 BsonFilter =
new BsonDocument();
1363 BsonFilter = Convert(
Filter, Serializer);
1365 return Process(Processor, Serializer, Collection, Offset, MaxCount, BsonFilter,
null, SortOrder);
1382 T ContinueAfter, params
string[] SortOrder)
1387 IMongoCollection<BsonDocument> Collection;
1388 FilterDefinition<BsonDocument> BsonFilter;
1390 if (
string.IsNullOrEmpty(CollectionName))
1391 Collection = this.defaultCollection;
1396 BsonFilter =
new BsonDocument();
1398 BsonFilter = Convert(
Filter, Serializer);
1400 return Process(Processor, Serializer, Collection, Offset, MaxCount, BsonFilter, ContinueAfter, SortOrder);
1416 params
string[] SortOrder)
1421 IMongoCollection<BsonDocument> Collection;
1423 if (
string.IsNullOrEmpty(CollectionName))
1424 Collection = this.defaultCollection;
1428 return Process(Processor, Serializer, Collection, Offset, MaxCount, BsonFilter,
null, SortOrder);
1447 IMongoCollection<BsonDocument> Collection;
1448 FilterDefinition<BsonDocument> BsonFilter;
1450 if (
string.IsNullOrEmpty(CollectionName))
1451 Collection = this.defaultCollection;
1456 BsonFilter =
new BsonDocument();
1458 BsonFilter = Convert(
Filter, Serializer);
1460 return Process(Processor, Serializer, Collection, Offset, MaxCount, BsonFilter,
null, SortOrder);
1477 T ContinueAfter, params
string[] SortOrder)
1481 IMongoCollection<BsonDocument> Collection;
1482 FilterDefinition<BsonDocument> BsonFilter;
1484 if (
string.IsNullOrEmpty(CollectionName))
1485 Collection = this.defaultCollection;
1490 BsonFilter =
new BsonDocument();
1492 BsonFilter = Convert(
Filter, Serializer);
1494 return Process(Processor, Serializer, Collection, Offset, MaxCount, BsonFilter, ContinueAfter, SortOrder);
1510 return this.
Process(Processor, CollectionName, Offset, MaxCount,
null, SortOrder);
1528 IMongoCollection<BsonDocument> Collection;
1529 FilterDefinition<BsonDocument> BsonFilter;
1531 if (
string.IsNullOrEmpty(CollectionName))
1532 Collection = this.defaultCollection;
1537 BsonFilter =
new BsonDocument();
1539 BsonFilter = Convert(
Filter, Serializer);
1541 return Process(Processor, Serializer, Collection, Offset, MaxCount, BsonFilter, SortOrder);
1545 int Offset,
int MaxCount, FilterDefinition<BsonDocument> BsonFilter, T ContinueAfter, params
string[] SortOrder)
1548 if (ContinueAfter is not
null)
1549 throw new NotImplementedException(
"Paginated searches not implemented in MongoDB provider.");
1551 IFindFluent<BsonDocument, BsonDocument> ResultSet = Collection.Find(BsonFilter);
1553 if (SortOrder.Length > 0)
1555 SortDefinition<BsonDocument> SortDefinition =
null;
1557 foreach (
string SortBy
in SortOrder)
1559 if (SortDefinition is
null)
1561 if (SortBy.StartsWith(
'-'))
1562 SortDefinition = Builders<BsonDocument>.Sort.Descending(Serializer.
ToShortName(SortBy[1..]));
1564 SortDefinition = Builders<BsonDocument>.Sort.Ascending(Serializer.
ToShortName(SortBy));
1568 if (SortBy.StartsWith(
'-'))
1569 SortDefinition = SortDefinition.Descending(Serializer.
ToShortName(SortBy[1..]));
1571 SortDefinition = SortDefinition.Ascending(Serializer.
ToShortName(SortBy));
1575 ResultSet = ResultSet.Sort(SortDefinition);
1579 ResultSet = ResultSet.Skip(Offset);
1581 if (MaxCount <
int.MaxValue)
1582 ResultSet = ResultSet.Limit(MaxCount);
1584 IAsyncCursor<BsonDocument> Cursor = await ResultSet.ToCursorAsync();
1585 BsonDeserializationArgs Args =
new()
1587 NominalType = typeof(T)
1590 bool Asynchronous = Processor.IsAsynchronous;
1593 while (await Cursor.MoveNextAsync())
1595 foreach (BsonDocument Document
in Cursor.Current)
1597 BsonDocumentReader Reader =
new(Document);
1598 BsonDeserializationContext Context = BsonDeserializationContext.CreateRoot(Reader);
1600 if (Serializer.
Deserialize(Context, Args) is T Obj)
1603 Continue = await Processor.ProcessAsync(Obj);
1605 Continue = Processor.Process(Obj);
1614 return await Processor.FlushAsync();
1616 return Processor.Flush();
1626 ObjectId ObjectId = await Serializer.
GetObjectId(Object,
false);
1628 IMongoCollection<BsonDocument> Collection;
1630 if (
string.IsNullOrEmpty(CollectionName))
1631 Collection = this.defaultCollection;
1635 BsonDocument Doc = Object.ToBsonDocument(Object.GetType(), Serializer);
1636 await Collection.ReplaceOneAsync(Builders<BsonDocument>.
Filter.Eq<ObjectId>(
"_id", ObjectId), Doc);
1645 return this.
Update((IEnumerable<object>)Objects);
1652 public async Task
Update(IEnumerable<object> Objects)
1654 foreach (
object Obj
in Objects)
1689 ObjectId ObjectId = await Serializer.
GetObjectId(Object,
false);
1691 IMongoCollection<BsonDocument> Collection;
1693 if (
string.IsNullOrEmpty(CollectionName))
1694 Collection = this.defaultCollection;
1698 await Collection.DeleteOneAsync(Builders<BsonDocument>.
Filter.Eq<ObjectId>(
"_id", ObjectId));
1707 return this.
Delete((IEnumerable<object>)Objects);
1714 public async Task
Delete(IEnumerable<object> Objects)
1716 foreach (
object Obj
in Objects)
1723 if (Callback is not
null)
1731 if (Callback is not
null)
1768 public async Task<IEnumerable<T>>
FindDelete<T>(
int Offset,
int MaxCount, params
string[] SortOrder)
1771 IEnumerable<T> Result = await this.
Find<T>(Offset, MaxCount, SortOrder);
1772 await this.
Delete(Result);
1789 IEnumerable<T> Result = await this.
Find<T>(Offset, MaxCount,
Filter, SortOrder);
1790 await this.
Delete(Result);
1803 public async Task<IEnumerable<object>>
FindDelete(
string Collection,
int Offset,
int MaxCount, params
string[] SortOrder)
1805 IEnumerable<object> Result = await this.
Find(Collection, Offset, MaxCount, SortOrder);
1806 await this.
Delete(Result);
1820 public async Task<IEnumerable<object>>
FindDelete(
string Collection,
int Offset,
int MaxCount,
Filter Filter, params
string[] SortOrder)
1822 IEnumerable<object> Result = await this.
Find(Collection, Offset, MaxCount,
Filter, SortOrder);
1823 await this.
Delete(Result);
1839 IEnumerable<T> Objects = await this.
FindDelete<T>(Offset, MaxCount, SortOrder);
1840 if (Callback is not
null)
1858 if (Callback is not
null)
1873 IEnumerable<object> Objects = await this.
FindDelete(Collection, Offset, MaxCount, SortOrder);
1874 if (Callback is not
null)
1890 IEnumerable<object> Objects = await this.
FindDelete(Collection, Offset, MaxCount,
Filter, SortOrder);
1891 if (Callback is not
null)
1900 public Task
Clear(
string CollectionName)
1902 IMongoCollection<BsonDocument> Collection = this.
GetCollection(CollectionName);
1903 return Collection.DeleteManyAsync(FilterDefinition<BsonDocument>.Empty);
1912 public async Task
AddIndex(
string CollectionName,
string[] FieldNames)
1914 IMongoCollection<BsonDocument> Collection;
1915 List<BsonDocument> Indices;
1917 if (
string.IsNullOrEmpty(CollectionName))
1922 IAsyncCursor<BsonDocument> Cursor = await Collection.Indexes.ListAsync();
1923 Indices = await Cursor.ToListAsync<BsonDocument>();
1925 await
ObjectSerializer.CheckIndexExists(Collection, Indices, FieldNames,
null);
1934 public async Task
RemoveIndex(
string CollectionName,
string[] FieldNames)
1936 IMongoCollection<BsonDocument> Collection;
1937 List<BsonDocument> Indices;
1939 if (
string.IsNullOrEmpty(CollectionName))
1944 IAsyncCursor<BsonDocument> Cursor = await Collection.Indexes.ListAsync();
1945 Indices = await Cursor.ToListAsync<BsonDocument>();
1959 IMongoCollection<BsonDocument> Collection;
1961 if (
string.IsNullOrEmpty(CollectionName))
1966 IAsyncCursor<BsonDocument> Cursor = await Collection.Indexes.ListAsync();
1969 while (await Cursor.MoveNextAsync())
1971 foreach (BsonDocument Index
in Cursor.Current)
1975 foreach (BsonElement E
in Index.Elements)
1977 if (E.Name !=
"key")
1982 foreach (BsonElement E2
in E.Value.AsBsonDocument.Elements)
1985 if (E2.Value.IsInt32 || E2.Value.IsInt64 || E2.Value.IsDouble)
1987 double v = E2.Value.ToDouble();
1989 FieldNames.
Add(
"-" + E2.Name);
1991 FieldNames.Add(E2.Name);
1993 else if (E2.Value.IsString)
1996 FieldNames.Add(E2.Name);
2001 FieldNames.Add(E2.Name);
2008 if (FieldNames is not
null && FieldNames.Count > 0)
2009 Result.
Add([.. FieldNames]);
2023 public Task<string[]>
Analyze(XmlWriter Output,
string XsltPath,
string ProgramDataFolder,
bool ExportData)
2025 return this.
Analyze(Output, XsltPath, ProgramDataFolder, ExportData,
false);
2036 public Task<string[]>
Analyze(XmlWriter Output,
string XsltPath,
string ProgramDataFolder,
bool ExportData,
ProfilerThread Thread)
2038 return this.
Analyze(Output, XsltPath, ProgramDataFolder, ExportData,
false, Thread);
2048 public Task<string[]>
Repair(XmlWriter Output,
string XsltPath,
string ProgramDataFolder,
bool ExportData)
2050 return this.
Analyze(Output, XsltPath, ProgramDataFolder, ExportData,
true);
2061 public Task<string[]>
Repair(XmlWriter Output,
string XsltPath,
string ProgramDataFolder,
bool ExportData,
ProfilerThread Thread)
2063 return this.
Analyze(Output, XsltPath, ProgramDataFolder, ExportData,
true, Thread);
2074 public Task<string[]>
Analyze(XmlWriter Output,
string XsltPath,
string ProgramDataFolder,
bool ExportData,
bool Repair)
2076 return this.
Analyze(
null, XsltPath, ProgramDataFolder, ExportData,
Repair,
null);
2088 public async Task<string[]>
Analyze(XmlWriter Output,
string XsltPath,
string ProgramDataFolder,
bool ExportData,
bool Repair,
2092 Output.WriteStartDocument();
2094 if (!
string.IsNullOrEmpty(XsltPath))
2096 if (File.Exists(XsltPath))
2100 byte[] XsltBin = File.ReadAllBytes(XsltPath);
2102 Output.WriteProcessingInstruction(
"xml-stylesheet",
"type=\"text/xsl\" href=\"data:text/xsl;base64," +
2103 System.Convert.ToBase64String(XsltBin) +
"\"");
2107 Output.WriteProcessingInstruction(
"xml-stylesheet",
"type=\"text/xsl\" href=\"" + Encode(XsltPath) +
"\"");
2111 Output.WriteProcessingInstruction(
"xml-stylesheet",
"type=\"text/xsl\" href=\"" + Encode(XsltPath) +
"\"");
2114 Output.WriteStartElement(
"DatabaseStatistics",
"http://waher.se/Schema/Persistence/Statistics.xsd");
2116 foreach (
string CollectionName
in (await this.database.ListCollectionNamesAsync()).ToEnumerable())
2118 Thread?.NewState(CollectionName);
2120 IMongoCollection<BsonDocument> Collection = this.database.GetCollection<BsonDocument>(CollectionName);
2122 Output.WriteStartElement(
"File");
2123 Output.WriteAttributeString(
"id", Collection.CollectionNamespace.FullName);
2124 Output.WriteAttributeString(
"collectionName", CollectionName);
2125 Output.WriteAttributeString(
"count", (await Collection.CountDocumentsAsync(Builders<BsonDocument>.Filter.Empty)).ToString());
2127 if (Collection.Settings.WriteEncoding is not
null)
2128 Output.WriteAttributeString(
"encoding", Collection.Settings.WriteEncoding.WebName);
2130 if (Collection.Settings.WriteConcern.WTimeout.HasValue)
2131 Output.WriteAttributeString(
"timeoutMs", ((
int)Collection.Settings.WriteConcern.WTimeout.Value.TotalMilliseconds).ToString());
2133 foreach (BsonDocument Index
in (await Collection.Indexes.ListAsync()).ToEnumerable())
2135 List<string> FieldNames = [];
2137 Output.WriteStartElement(
"Index");
2139 foreach (BsonElement E
in Index.Elements)
2144 foreach (BsonElement E2
in E.Value.AsBsonDocument.Elements)
2146 if (E2.Value.AsInt32 < 0)
2147 FieldNames.Add(
"-" + E2.Name);
2149 FieldNames.Add(E2.Name);
2154 Output.WriteAttributeString(
"id", E.Value.AsString);
2159 foreach (
string Field
in FieldNames)
2160 Output.WriteElementString(
"Field", Field);
2162 Output.WriteEndElement();
2165 Output.WriteEndElement();
2168 Output.WriteEndElement();
2169 Output.WriteEndDocument();
2182 public Task<string[]>
Repair(params
string[] CollectionNames)
2184 return Task.FromResult<
string[]>([]);
2195 return Task.FromResult<
string[]>([]);
2198 private static string Encode(
string s)
2201 Replace(
"&",
"&").
2202 Replace(
"<",
"<").
2203 Replace(
">",
">").
2204 Replace(
"\"",
""").
2205 Replace(
"'",
"'");
2216 return this.
Export(Output, CollectionNames,
null);
2237 BsonDeserializationArgs Args =
new()
2242 foreach (
string CollectionName
in (await this.database.ListCollectionNamesAsync()).ToEnumerable())
2244 if (CollectionNames is not
null && Array.IndexOf(CollectionNames, CollectionName) < 0)
2247 if (
Filter is not
null && !
Filter.CanExportCollection(CollectionName))
2252 IMongoCollection<BsonDocument> Collection = this.database.GetCollection<BsonDocument>(CollectionName);
2258 foreach (BsonDocument Index
in (await Collection.Indexes.ListAsync()).ToEnumerable())
2263 foreach (BsonElement E
in Index.Elements)
2265 if (E.Name ==
"key")
2267 foreach (BsonElement E2
in E.Value.AsBsonDocument.Elements)
2281 foreach (BsonDocument Doc
in (await Collection.FindAsync<BsonDocument>(Builders<BsonDocument>.Filter.Empty)).ToEnumerable())
2283 BsonDocumentReader Reader =
new(Doc);
2284 BsonDeserializationContext Context = BsonDeserializationContext.CreateRoot(Reader);
2286 object Object = Serializer.
Deserialize(Context, Args);
2290 if (
Filter is not
null && !
Filter.CanExportObject(Obj))
2293 if (await Output.
StartObject(Obj.ObjectId.ToString(), Obj.TypeName) is
null)
2297 foreach (KeyValuePair<string, object> P
in Obj)
2299 if (P.Value is ObjectId ObjectId)
2311 catch (Exception ex)
2314 if (!await ReportException(ex, Output))
2325 else if (Object is not
null)
2327 if (!await Output.
ReportError(
"Unable to load object " + Doc[
"_id"].AsString +
"."))
2332 catch (Exception ex)
2335 if (!await ReportException(ex, Output))
2347 catch (Exception ex)
2350 if (!await ReportException(ex, Output))
2363 private static async Task<bool> ReportException(Exception ex,
IDatabaseExport Output)
2367 if (ex is AggregateException ex2)
2369 foreach (Exception ex3
in ex2.InnerExceptions)
2391 return this.Iterate(Recipient, CollectionNames,
null);
2406 await Recipient.StartDatabase();
2410 BsonDeserializationArgs Args =
new()
2415 foreach (
string CollectionName
in (await this.database.ListCollectionNamesAsync()).ToEnumerable())
2417 if (CollectionNames is not
null && Array.IndexOf(CollectionNames, CollectionName) < 0)
2420 Thread?.NewState(CollectionName);
2422 IMongoCollection<BsonDocument> Collection = this.database.GetCollection<BsonDocument>(CollectionName);
2424 await Recipient.StartCollection(CollectionName);
2427 foreach (BsonDocument Doc
in (await Collection.FindAsync<BsonDocument>(Builders<BsonDocument>.Filter.Empty)).ToEnumerable())
2429 BsonDocumentReader Reader =
new(Doc);
2430 BsonDeserializationContext Context = BsonDeserializationContext.CreateRoot(Reader);
2432 object Object = Serializer.
Deserialize(Context, Args);
2434 if (Object is T Obj)
2435 await Recipient.ProcessObject(Obj);
2436 else if (Object is not
null)
2438 ObjectId ObjectId = await Serializer.
GetObjectId(Object,
false);
2439 if (ObjectId != ObjectId.Empty)
2440 await Recipient.IncompatibleObject(ObjectId);
2444 catch (Exception ex)
2446 Thread?.Exception(ex);
2447 ReportException(ex, Recipient);
2451 await Recipient.EndCollection();
2455 catch (Exception ex)
2457 Thread?.Exception(ex);
2458 ReportException(ex, Recipient);
2462 await Recipient.EndDatabase();
2471 ex = Events.Log.UnnestException(ex);
2473 if (ex is AggregateException ex2)
2475 foreach (Exception ex3
in ex2.InnerExceptions)
2476 Recipient.ReportException(ex3);
2479 Recipient.ReportException(ex);
2487 return Task.CompletedTask;
2495 return Task.CompletedTask;
2503 return Task.CompletedTask;
2511 return Task.CompletedTask;
2519 return Task.CompletedTask;
2538 List<string> Collections = [];
2540 foreach (
string CollectionName
in (await this.database.ListCollectionNamesAsync()).ToEnumerable())
2542 if (CollectionName.StartsWith(
"DICT_"))
2543 Collections.Add(CollectionName);
2546 return [.. Collections];
2555 public Task<IPersistedQueue>
GetQueue(
string QueueName,
bool CanBeNull)
2558 ??
throw new NotSupportedException(
"No queue collection creator found for database provider.");
2560 return Collection.
GetQueue(
this, QueueName, CanBeNull);
2570 FilterDefinition<BsonDocument> BsonFilter = Builders<BsonDocument>.Filter.Ne<
string>(
"QueueName",
null);
2572 using IAsyncCursor<
string> Cursor = await Collection.DistinctAsync<
string>(
"QueueName", BsonFilter);
2574 return [.. await Cursor.ToListAsync()];
2583 List<string> Collections = [];
2585 foreach (
string CollectionName
in (await this.database.ListCollectionNamesAsync()).ToEnumerable())
2587 if (!CollectionName.StartsWith(
"DICT_"))
2588 Collections.Add(CollectionName);
2591 return [.. Collections];
2623 public async Task<bool>
IsLabel(
string CollectionName,
string Label)
2625 IMongoCollection<BsonDocument> Collection = this.
GetCollection(CollectionName);
2626 FilterDefinition<BsonDocument> BsonFilter = Builders<BsonDocument>.Filter.Ne<
string>(Label,
null);
2627 IFindFluent<BsonDocument, BsonDocument> ResultSet = Collection.Find<BsonDocument>(BsonFilter);
2629 return await ResultSet.SingleAsync<BsonDocument>() is not
null;
2638 throw new NotImplementedException();
2655 return await SerializerEx.GetObjectId(Object,
false);
2667 lock (this.collections)
2669 this.collections.Remove(CollectionName);
2671 if (CollectionName == this.lastCollectionName)
2673 this.lastCollection =
null;
2674 this.lastCollectionName =
string.Empty;
2678 return this.database.DropCollectionAsync(CollectionName);
2692 string CollectionName = Serializer.CollectionName(Object);
2694 BsonDocument Doc = Object.ToBsonDocument(Object.GetType(), Serializer);
2698 BsonDocumentReader Reader =
new(Doc);
2699 BsonDeserializationContext Context = BsonDeserializationContext.CreateRoot(Reader);
2700 BsonDeserializationArgs Args =
new()
2707 Obj.ArchivingTime = Serializer.GetArchivingTimeDays(Object);
2708 return Task.FromResult(Obj);
2711 throw new InvalidOperationException(
"Unable to generalize object.");
2722 return Task.FromResult<
object>(
null);
2726 return Task.FromResult<
object>(Object);
2729 string CollectionName = Serializer.CollectionName(Object);
2731 BsonDocument Doc = Object.ToBsonDocument(Object.GetType(), Serializer);
2735 BsonDocumentReader Reader =
new(Doc);
2736 BsonDeserializationContext Context = BsonDeserializationContext.CreateRoot(Reader);
2737 BsonDeserializationArgs Args =
new()
2742 return Task.FromResult<
object>(Serializer.Deserialize(Context, Args));
2751 SortedDictionary<string, bool> Sorted =
new(StringComparer.OrdinalIgnoreCase);
2753 lock (this.collections)
2762 string[] Result =
new string[Sorted.Count];
2763 Sorted.Keys.CopyTo(Result, 0);
Static class managing the application event log. Applications and services log events on this static ...
static Exception UnnestException(Exception Exception)
Unnests an exception, to extract the relevant inner exception.
Represents a case-insensitive string.
This filter selects objects that conform to all child-filters provided.
Abstract base class for filters having a single child-filters.
Filter ChildFilter
Child filter.
Abstract base class for filters having a variable number of child-filters.
Filter[] ChildFilters
Child filters.
This filter selects objects that have a named field equal to a given value.
This filter selects objects that have a named field greater or equal to a given value.
This filter selects objects that have a named field greater than a given value.
string FieldName
FIeld Name.
This filter selects objects that have a named field lesser or equal to a given value.
This filter selects objects that have a named field lesser than a given value.
This filter selects objects that have a named field matching a given regular expression.
string RegularExpression
Regular expression.
This filter selects objects that have a named field not equal to a given value.
Abstract base class for all field filters operating on a constant value.
Base class for all filter classes.
Filter()
Base class for all filter classes.
This filter selects objects that does not conform to the child-filter provided.
This filter selects objects that conform to any of the child-filters provided.
MongoDB database provider.
Task Delete(params object[] Objects)
Deletes a collection of objects in the database.
Task Clear(string CollectionName)
Clears a collection of all objects.
Task UpdateLazy(object Object, ObjectCallback Callback)
Updates an object in the database, if unlocked. If locked, object will be updated at next opportunity...
Task< string[]> Analyze(XmlWriter Output, string XsltPath, string ProgramDataFolder, bool ExportData, ProfilerThread Thread)
Analyzes the database and exports findings to XML.
MongoDBProvider(string DatabaseName, string DefaultCollectionName)
MongoDB database provider, for a local MongoDB database.
Task< string[]> Repair(XmlWriter Output, string XsltPath, string ProgramDataFolder, bool ExportData, ProfilerThread Thread)
Analyzes the database and repairs it if necessary. Results are exported to XML.
async Task< object > TryLoadObject(string CollectionName, object ObjectId)
Tries to load an object given its Object ID ObjectId and its collection name CollectionName .
Task< IPage< T > > FindNext< T >(IPage< T > Page)
Finds the next page of objects of a given class T .
Task< T > TryLoadObject< T >(object ObjectId)
Tries to load an object given its Object ID ObjectId and its base type T .
async Task< bool > IsLabel(string CollectionName, string Label)
Checks if a string is a label in a given collection.
Task< string[]> Repair(params string[] CollectionNames)
Repairs a set of collections.
async Task DeleteLazy< T >(int Offset, int MaxCount, string[] SortOrder, ObjectsCallback Callback)
Finds objects of a given class T and deletes them in the same atomic operation.
Task DropCollection(string CollectionName)
Drops a collection, if it exist.
Task< string[]> Analyze(XmlWriter Output, string XsltPath, string ProgramDataFolder, bool ExportData)
Analyzes the database and exports findings to XML.
int ObjectIdByteCount
Number of bytes used by an Object ID.
Task StartBulk()
Starts bulk-proccessing of data. Must be followed by a call to EndBulk.
Task< bool > Export(IDatabaseExport Output, string[] CollectionNames)
Performs an export of the database.
Task Iterate< T >(IDatabaseIteration< T > Recipient, string[] CollectionNames)
Performs an iteration of contents of the entire database.
string DefaultCollectionName
Default collection name.
async Task< string[]> Analyze(XmlWriter Output, string XsltPath, string ProgramDataFolder, bool ExportData, bool Repair, ProfilerThread Thread)
Analyzes the database and exports findings to XML.
Task DeleteLazy(object Object, ObjectCallback Callback)
Deletes an object in the database, if unlocked. If locked, object will be deleted at next opportunity...
Task Update(params object[] Objects)
Updates a collection of objects in the database.
async Task Update(object Object)
Updates an object in the database.
IMongoCollection< BsonDocument > DefaultCollection
Default collection.
Task< IPersistedQueue > GetQueue(string QueueName, bool CanBeNull)
Gets a persistent dictionary containing objects in a collection.
Task DeleteLazy(IEnumerable< object > Objects, ObjectsCallback Callback)
Deletes a collection of objects in the database, if unlocked. If locked, objects will be deleted at n...
async Task< IPage< object > > FindFirst(string Collection, int PageSize, params string[] SortOrder)
Finds the first page of objects in a given collection.
Task< bool > Process< T >(IProcessor< T > Processor, int Offset, int MaxCount, params string[] SortOrder)
Processes objects of a given class T .
async Task Insert(IEnumerable< object > Objects)
Inserts a collection of objects into the database.
Task Insert(params object[] Objects)
Inserts a collection of objects into the database.
async Task< string[]> GetDictionaries()
Gets an array of available dictionary collections.
Task< IPersistentDictionary > GetDictionary(string Collection)
Gets a persistent dictionary containing objects in a collection.
string Id
An ID of the files provider. It's unique, and constant during the life-time of the MongoDBProvider cl...
async Task< IEnumerable< object > > FindDelete(string Collection, int Offset, int MaxCount, Filter Filter, params string[] SortOrder)
Finds objects in a given collection and deletes them in the same atomic operation.
Task UpdateLazy(IEnumerable< object > Objects, ObjectsCallback Callback)
Updates a collection of objects in the database, if unlocked. If locked, objects will be updated at n...
Task< bool > Process(IProcessor< object > Processor, string CollectionName, int Offset, int MaxCount, Filter Filter, params string[] SortOrder)
Processes objects in a given collection.
async Task Delete(object Object)
Deletes an object in the database.
MongoDBProvider(string HostName, int Port, string DatabaseName, string DefaultCollectionName)
MongoDB database provider.
async Task< string[][]> GetIndices(string CollectionName)
Removes an index from a collection, if one exist.
async Task RemoveIndex(string CollectionName, string[] FieldNames)
Removes an index from a collection, if one exist.
Task< string > GetCollection(Type Type)
Gets the collection corresponding to a given type.
async Task< IEnumerable< T > > FindDelete< T >(int Offset, int MaxCount, params string[] SortOrder)
Finds objects of a given class T and deletes them in the same atomic operation.
Task DeleteLazy(object[] Objects, ObjectsCallback Callback)
Deletes a collection of objects in the database, if unlocked. If locked, objects will be deleted at n...
MongoDBProvider(MongoClientSettings Settings, string DatabaseName, string DefaultCollectionName)
MongoDB database provider.
async Task DeleteLazy(string Collection, int Offset, int MaxCount, Filter Filter, string[] SortOrder, ObjectsCallback Callback)
Finds objects in a given collection and deletes them in the same atomic operation.
IObjectSerializer GetObjectSerializer(Type Type)
Returns a serializer for a given type.
Task< string[]> GetLabels(string Collection)
Gets an array of available labels for a collection.
Task Stop()
Called when processing ends.
async Task< IPage< T > > FindFirst< T >(int PageSize, params string[] SortOrder)
Finds the first page of objects of a given class T .
async Task< object > TryGetObjectId(object Object)
Tries to get the Object ID of an object, if it exists.
Task< IPage< object > > FindNext(IPage< object > Page)
Finds the next page of objects in a given collection.
ObjectSerializer GetObjectSerializerEx(object Object)
Gets the object serializer corresponding to a specific object.
Task< IEnumerable< T > > Find< T >(int Offset, int MaxCount, params string[] SortOrder)
Finds objects of a given class T .
Task< object > Specialize(GenericObject Object)
Creates a specialized representation of a generic object.
Task Start()
Called when processing starts.
async Task< IPage< object > > FindFirst(string Collection, int PageSize, Filter Filter, params string[] SortOrder)
Finds the first page of objects in a given collection.
MongoDBProvider(string HostName, string DatabaseName, string DefaultCollectionName)
MongoDB database provider.
string[] GetExcludedCollections()
Gets an array of collections that should be excluded from backups.
async Task< string[]> GetQueues()
Gets an array of available queue names.
async Task< IEnumerable< object > > FindDelete(string Collection, int Offset, int MaxCount, params string[] SortOrder)
Finds objects in a given collection and deletes them in the same atomic operation.
Task UpdateLazy(object[] Objects, ObjectsCallback Callback)
Updates a collection of objects in the database, if unlocked. If locked, objects will be updated at n...
Task< string[]> Analyze(XmlWriter Output, string XsltPath, string ProgramDataFolder, bool ExportData, bool Repair)
Analyzes the database and exports findings to XML.
Task InsertLazy(IEnumerable< object > Objects, ObjectsCallback Callback)
Inserts an object into the database, if unlocked. If locked, object will be inserted at next opportun...
Task< bool > Process(IProcessor< object > Processor, string CollectionName, int Offset, int MaxCount, params string[] SortOrder)
Processes objects in a given collection.
MongoClient Client
Underlying MongoDB client.
Task Flush()
Persists any pending changes.
Task< IEnumerable< object > > Find(string CollectionName, int Offset, int MaxCount, Filter Filter, params string[] SortOrder)
Finds objects in a given collection.
async Task Insert(object Object)
Inserts an object into the database.
async Task AddIndex(string CollectionName, string[] FieldNames)
Adds an index to a collection, if one does not already exist.
Task EndBulk()
Ends bulk-processing of data. Must be called once for every call to StartBulk.
Task InsertLazy(object Object, ObjectCallback Callback)
Inserts an object into the database, if unlocked. If locked, object will be inserted at next opportun...
Task< string[]> Repair(ProfilerThread Thread, params string[] CollectionNames)
Repairs a set of collections.
Task< string[]> Repair(XmlWriter Output, string XsltPath, string ProgramDataFolder, bool ExportData)
Analyzes the database and repairs it if necessary. Results are exported to XML.
Task< GenericObject > Generalize(object Object)
Creates a generalized representation of an object.
async Task Update(IEnumerable< object > Objects)
Updates a collection of objects in the database.
async Task Delete(IEnumerable< object > Objects)
Deletes a collection of objects in the database.
Task< IEnumerable< object > > Find(string CollectionName, int Offset, int MaxCount, params string[] SortOrder)
Finds objects in a given collection.
async Task< string[]> GetCollections()
Gets an array of available collections.
async Task< bool > Export(IDatabaseExport Output, string[] CollectionNames, ProfilerThread Thread)
Performs an export of the database.
Task InsertLazy(object[] Objects, ObjectsCallback Callback)
Inserts an object into the database, if unlocked. If locked, object will be inserted at next opportun...
IMongoCollection< BsonDocument > GetCollection(string CollectionName)
Gets a collection.
ObjectSerializer GetObjectSerializerEx(Type Type)
Gets the object serializer corresponding to a specific object.
async Task DeleteLazy(string Collection, int Offset, int MaxCount, string[] SortOrder, ObjectsCallback Callback)
Finds objects in a given collection and deletes them in the same atomic operation.
Task< string > GetCollection(object Object)
Gets the collection corresponding to a given object.
Contains a page of items.
Abstract base class for generated object serializers.
static Guid ObjectIdToGuid(ObjectId ObjectId)
Converts a MongoDB Object ID to a GUID
static ObjectId GuidToObjectId(Guid Guid)
Converts a GUID to a MongoDB Object ID
Provides a generic object serializer.
Serializes a type to BSON, taking into account attributes defined in Waher.Persistence....
virtual string CollectionName(object Object)
Name of collection objects of this type is to be stored in, if available. If not available,...
virtual bool IsDefaultValue(string FieldName, object Value)
Checks if a given field value corresponds to the default value for the corresponding field.
virtual bool TryGetFieldType(string FieldName, object Object, out Type FieldType)
Gets the type of a field or property of an object, given its name.
Type ValueType
Gets the type of the value.
virtual async Task< ObjectId > GetObjectId(object Value, bool InsertIfNotFound)
Gets the Object ID for a given object.
string ToShortName(string FieldName)
Converts a field name to its corresponding short name. If no explicit short name is available,...
virtual string ObjectIdMemberName
Mamber name of the field or property holding the Object ID, if any. If there are no such member,...
virtual bool HasObjectId(object Value)
If the class has an Object ID.
virtual bool HasObjectIdField
If the class has an Object ID field.
object Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
Deserializes a value.
bool BackupCollection
If the corresponding collection should be backed up or not.
static readonly DateTime UnixEpoch
UNIX Epoch, started at 1970-01-01, 00:00:00 (GMT)
Serializes an enumerated value value.
This class manages a string dictionary in a persisted storage.
Represents one item in a queue.
const string QueuedItemCollectionName
Collection name of queued items: QueuedItems
Generic object. Contains a sequence of properties.
string TypeName
Type name.
Implements an in-memory cache.
bool TryGetValue(KeyType Key, out ValueType Value)
Tries to get a value from the cache.
void Add(KeyType Key, ValueType Value)
Adds an item to the cache.
A chunked list is a linked list of chunks of objects of type T .
void Add(T Item)
Adds an item to the collection.
Static class that dynamically manages types and interfaces available in the runtime environment.
static Type GetType(string FullName)
Gets a type, given its full name.
static object[] NoParameters
Contains an empty array of parameter values.
static Type[] GetTypesImplementingInterface(string InterfaceFullName)
Gets all types implementing a given interface.
static ConstructorInfo GetDefaultConstructor(Type Type)
Gets the default constructor of a type, if one exists.
Class that keeps track of events and timing for one thread.
void Start()
Processing starts.
void Exception(System.Exception Exception)
Exception occurred
void Stop()
Processing starts.
void Idle()
Thread goes idle.
void NewState(string State)
Thread changes state.
Interface for database providers that can be plugged into the static Database class.
Interface for paginated results.
Persistent dictionary that can contain more entries than possible in the internal memory.
Interface for processors of objects.
Interface for object serializers.
Type ValueType
What type of object is being serialized.
Inteface for collections of persisted queues matching a given database provider.
Task< IPersistedQueue > GetQueue(IDatabaseProvider Provider, string QueueName, bool CanBeNull)
Gets a persisted queue with the specified name. If one is not found, a new one is created.
Interface for database exports that filter objects.
Interface for database exports.
Task< bool > EndCollection()
Is called when a collection is finished.
Task< bool > ReportException(Exception Exception)
Is called when an exception has occurred.
Task< bool > ReportProperty(string PropertyName, object PropertyValue)
Is called when a property is reported.
Task< bool > EndObject()
Is called when an object is finished.
Task< bool > EndIndex()
Is called when an index in a collection is finished.
Task< bool > ReportError(string Message)
Is called when an error is reported.
Task< bool > ReportIndexField(string FieldName, bool Ascending)
Is called when a field in an index is reported.
Task< bool > StartIndex()
Is called when an index in a collection is started.
Task< bool > EndDatabase()
Is called when export of database is finished.
Task< string > StartObject(string ObjectId, string TypeName)
Is called when an object is started.
Task< bool > StartDatabase(IDatabaseProvider Provider)
Is called when export of database is started.
Task< bool > StartCollection(string CollectionName)
Is called when a collection is started.
Interface for iterations of database contents.
delegate void ObjectCallback(object Object)
Method called when a process has completed for an object.
delegate void ObjectsCallback(IEnumerable< object > Objects)
Method called when a process has completed for a set of objects.