diff --git a/samples/MongoDBSample/Program.cs b/samples/MongoDBSample/Program.cs index 3aa03a9..89347bb 100644 --- a/samples/MongoDBSample/Program.cs +++ b/samples/MongoDBSample/Program.cs @@ -1,5 +1,6 @@ using MongoDB.Bson.Serialization.Attributes; using MongoDB.Driver; +using MongoDB.Driver.Linq; Console.WriteLine("Hello World!"); diff --git a/src/Tingle.AspNetCore.DataProtection.MongoDB/Tingle.AspNetCore.DataProtection.MongoDB.csproj b/src/Tingle.AspNetCore.DataProtection.MongoDB/Tingle.AspNetCore.DataProtection.MongoDB.csproj index 98efd8e..d853175 100644 --- a/src/Tingle.AspNetCore.DataProtection.MongoDB/Tingle.AspNetCore.DataProtection.MongoDB.csproj +++ b/src/Tingle.AspNetCore.DataProtection.MongoDB/Tingle.AspNetCore.DataProtection.MongoDB.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/Tingle.Extensions.Caching.MongoDB/Tingle.Extensions.Caching.MongoDB.csproj b/src/Tingle.Extensions.Caching.MongoDB/Tingle.Extensions.Caching.MongoDB.csproj index 10d704e..813258c 100644 --- a/src/Tingle.Extensions.Caching.MongoDB/Tingle.Extensions.Caching.MongoDB.csproj +++ b/src/Tingle.Extensions.Caching.MongoDB/Tingle.Extensions.Caching.MongoDB.csproj @@ -16,7 +16,7 @@ For more information, refer to https://www.mongodb.com/. - + diff --git a/src/Tingle.Extensions.MongoDB/Extensions/BuildersExtensions.cs b/src/Tingle.Extensions.MongoDB/Extensions/BuildersExtensions.cs index f87e9be..12c356d 100644 --- a/src/Tingle.Extensions.MongoDB/Extensions/BuildersExtensions.cs +++ b/src/Tingle.Extensions.MongoDB/Extensions/BuildersExtensions.cs @@ -82,8 +82,16 @@ private static StringFieldDefinition CreateFieldDefinition(Express { var collection = new ExpressionFieldDefinition(collectionExpression); var child = new ExpressionFieldDefinition(memberExpression); - var collectionDefinition = collection.Render(BsonSerializer.LookupSerializer(), BsonSerializer.SerializerRegistry); - var childDefinition = child.Render(BsonSerializer.LookupSerializer(), BsonSerializer.SerializerRegistry); + var collectionDefinition = collection.Render(new RenderArgs + { + DocumentSerializer = BsonSerializer.LookupSerializer(), + SerializerRegistry = BsonSerializer.SerializerRegistry, + }); + var childDefinition = child.Render(new RenderArgs + { + DocumentSerializer = BsonSerializer.LookupSerializer(), + SerializerRegistry = BsonSerializer.SerializerRegistry, + }); var fieldDefinition = new StringFieldDefinition(collectionDefinition.FieldName + "." + childDefinition.FieldName); return fieldDefinition; diff --git a/src/Tingle.Extensions.MongoDB/Extensions/IMongoQueryableExtensions.cs b/src/Tingle.Extensions.MongoDB/Extensions/IMongoQueryableExtensions.cs deleted file mode 100644 index 90dca13..0000000 --- a/src/Tingle.Extensions.MongoDB/Extensions/IMongoQueryableExtensions.cs +++ /dev/null @@ -1,229 +0,0 @@ -using MongoDB.Driver; -using MongoDB.Driver.Linq; -using System.Linq.Expressions; - -namespace System.Linq; - -/// -/// Extension methods on -/// -public static class IMongoQueryableExtensions -{ - /// - /// Returns the number of elements in a sequence. - /// This method removes the need to convert instances of to . - /// - /// The type of the elements of source. - /// The that contains the elements to be counted. - /// The cancellation token. - /// The number of elements in the input sequence. - public static Task LongCountInMongoAsync(this IQueryable source, CancellationToken cancellationToken = default) - { - ArgumentNullException.ThrowIfNull(source); - - // cast to IMongoQueryable, if not possible, a type cast exception is thrown - var mq = (IMongoQueryable)source; - - // execute the async operation - return mq.LongCountAsync(cancellationToken); - } - - /// - /// Returns the number of elements in the specified sequence that satisfies a condition. - /// This method removes the need to convert instances of to . - /// - /// The type of the elements of source. - /// The that contains the elements to be counted. - /// A function to test an element for a condition. - /// The cancellation token. - /// The number of elements in the sequence that satisfies the condition in the predicate function. - public static Task LongCountInMongoAsync(this IQueryable source, Expression> predicate, CancellationToken cancellationToken = default) - { - ArgumentNullException.ThrowIfNull(source); - - // cast to IMongoQueryable, if not possible, a type cast exception is thrown - var mq = (IMongoQueryable)source; - - // execute the async operation - return mq.LongCountAsync(predicate, cancellationToken); - } - - /// - /// Returns a list containing all the documents returned from Mongo. - /// This method removes the need to convert instances of to . - /// - /// The type of the document. - /// An . - /// The cancellation token. - /// A Task whose value is the list of documents. - public static Task> ToListInMongoAsync(this IQueryable source, CancellationToken cancellationToken = default) - { - ArgumentNullException.ThrowIfNull(source); - - // cast to IMongoQueryable, if not possible, a type cast exception is thrown - var mq = (IMongoQueryable)source; - - // execute the async operation - return mq.ToListAsync(cancellationToken); - } - - /// - /// Returns the first element of a sequence. - /// This method removes the need to convert instances of to . - /// - /// The type of the elements of source. - /// An to return the first element of. - /// The cancellation token. - /// The first element in source. - public static Task FirstInMongoAsync(this IQueryable source, CancellationToken cancellationToken = default) - { - ArgumentNullException.ThrowIfNull(source); - - // cast to IMongoQueryable, if not possible, a type cast exception is thrown - var mq = (IMongoQueryable)source; - - // execute the async operation - return mq.FirstAsync(cancellationToken); - } - - /// - /// Returns the first element of a sequence that satisfies a specified condition. - /// This method removes the need to convert instances of to . - /// - /// The type of the elements of source. - /// An to return an element from. - /// A function to test an element for a condition. - /// The cancellation token. - /// The first element in source that passes the test in predicate. - public static Task FirstInMongoAsync(this IQueryable source, Expression> predicate, CancellationToken cancellationToken = default) - { - ArgumentNullException.ThrowIfNull(source); - - // cast to IMongoQueryable, if not possible, a type cast exception is thrown - var mq = (IMongoQueryable)source; - - // execute the async operation - return mq.FirstAsync(predicate, cancellationToken); - } - - /// - /// Returns the first element of a sequence, or a default value if the sequence contains no elements. - /// This method throws an exception if there is more than one element in the sequence. - /// This method removes the need to convert instances of to . - /// - /// The type of the elements of source. - /// An to return the first element of. - /// The cancellation token. - /// The first element of the input sequence, or default(T) if the sequence contains no elements. - public static Task FirstOrDefaultInMongoAsync(this IQueryable source, CancellationToken cancellationToken = default) - { - ArgumentNullException.ThrowIfNull(source); - - // cast to IMongoQueryable, if not possible, a type cast exception is thrown - var mq = (IMongoQueryable)source; - - // execute the async operation - return mq.FirstOrDefaultAsync(cancellationToken); - } - - /// - /// Returns the first element of a sequence that satisfies a specified condition or a default value if no such element is found. - /// This method throws an exception if there is more than one element in the sequence. - /// This method removes the need to convert instances of to . - /// - /// The type of the elements of source. - /// An to return a first element from. - /// A function to test an element for a condition. - /// The cancellation token. - /// The first element of the input sequence that satisfies the condition in predicate, or default(T) if no such element is found. - public static Task FirstOrDefaultInMongoAsync(this IQueryable source, Expression> predicate, CancellationToken cancellationToken = default) - { - ArgumentNullException.ThrowIfNull(source); - - // cast to IMongoQueryable, if not possible, a type cast exception is thrown - var mq = (IMongoQueryable)source; - - // execute the async operation - return mq.FirstOrDefaultAsync(predicate, cancellationToken); - } - - /// - /// Returns the only element of a sequence from Mongo, and throws an exception if there is not exactly one element in the sequence. - /// This method removes the need to convert instances of to . - /// - /// The type of the elements of source. - /// An to return the single element of. - /// The cancellation token. - /// The single element of the input sequence. - public static Task SingleInMongoAsync(this IQueryable source, CancellationToken cancellationToken = default) - { - ArgumentNullException.ThrowIfNull(source); - - // cast to IMongoQueryable, if not possible, a type cast exception is thrown - var mq = (IMongoQueryable)source; - - // execute the async operation - return mq.SingleAsync(cancellationToken); - } - - /// - /// Returns the only element of a sequence from Mongo, and throws an exception if there is not exactly one element in the sequence. - /// This method removes the need to convert instances of to . - /// - /// The type of the elements of source. - /// An to return a single element from. - /// A function to test an element for a condition. - /// The cancellation token. - /// The single element of the input sequence that satisfies the condition in predicate. - public static Task SingleInMongoAsync(this IQueryable source, Expression> predicate, CancellationToken cancellationToken = default) - { - ArgumentNullException.ThrowIfNull(source); - - // cast to IMongoQueryable, if not possible, a type cast exception is thrown - var mq = (IMongoQueryable)source; - - // execute the async operation - return mq.SingleAsync(predicate, cancellationToken); - } - - /// - /// Returns the only element of a sequence from Mongo, or a default value if the sequence is empty. - /// This method throws an exception if there is more than one element in the sequence. - /// This method removes the need to convert instances of to . - /// - /// The type of the elements of source. - /// An to return the single element of. - /// The cancellation token. - /// The single element of the input sequence, or default(T) if the sequence contains no elements. - public static Task SingleOrDefaultInMongoAsync(this IQueryable source, CancellationToken cancellationToken = default) - { - ArgumentNullException.ThrowIfNull(source); - - // cast to IMongoQueryable, if not possible, a type cast exception is thrown - var mq = (IMongoQueryable)source; - - // execute the async operation - return mq.SingleOrDefaultAsync(cancellationToken); - } - - /// - /// Returns the only element of a sequence from Mongo, or a default value if the sequence is empty. - /// This method throws an exception if there is more than one element in the sequence. - /// This method removes the need to convert instances of to . - /// - /// The type of the elements of source. - /// An to return a single element from. - /// A function to test an element for a condition. - /// The cancellation token. - /// The single element of the input sequence that satisfies the condition in predicate, or default(T) if no such element is found. - public static Task SingleOrDefaultInMongoAsync(this IQueryable source, Expression> predicate, CancellationToken cancellationToken = default) - { - ArgumentNullException.ThrowIfNull(source); - - // cast to IMongoQueryable, if not possible, a type cast exception is thrown - var mq = (IMongoQueryable)source; - - // execute the async operation - return mq.SingleOrDefaultAsync(predicate, cancellationToken); - } -} diff --git a/src/Tingle.Extensions.MongoDB/Serialization/Serializers/JsonElementBsonSerializer.cs b/src/Tingle.Extensions.MongoDB/Serialization/Serializers/JsonElementBsonSerializer.cs index b5f6ee2..35fa4cc 100644 --- a/src/Tingle.Extensions.MongoDB/Serialization/Serializers/JsonElementBsonSerializer.cs +++ b/src/Tingle.Extensions.MongoDB/Serialization/Serializers/JsonElementBsonSerializer.cs @@ -18,9 +18,7 @@ internal class JsonElementBsonSerializer : StructSerializerBase /// Without this, ObjectIDs, Dates, and Integers are output as {"_id": ObjectId(ds8f7s9d87f89sd9f8d9f7sd9f9s8d)}, /// {"date": ISODate("2020-04-14 14:30:00:000")}, {"int": NumberInt(130)} and respectively, which is not valid JSON /// -#pragma warning disable CS0618 // Type or member is obsolete - internal static readonly JsonWriterSettings settings = new() { OutputMode = JsonOutputMode.Strict, }; -#pragma warning restore CS0618 // Type or member is obsolete + internal static readonly JsonWriterSettings settings = new() { OutputMode = JsonOutputMode.CanonicalExtendedJson, }; /// public override JsonElement Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) diff --git a/src/Tingle.Extensions.MongoDB/Tingle.Extensions.MongoDB.csproj b/src/Tingle.Extensions.MongoDB/Tingle.Extensions.MongoDB.csproj index 2ef72cb..52ca287 100644 --- a/src/Tingle.Extensions.MongoDB/Tingle.Extensions.MongoDB.csproj +++ b/src/Tingle.Extensions.MongoDB/Tingle.Extensions.MongoDB.csproj @@ -15,7 +15,7 @@ - + diff --git a/tests/Tingle.Extensions.MongoDB.Tests/Serialization/Conventions/DateTimeOffsetRepresentationConventionTests.cs b/tests/Tingle.Extensions.MongoDB.Tests/Serialization/Conventions/DateTimeOffsetRepresentationConventionTests.cs index 971695a..7951645 100644 --- a/tests/Tingle.Extensions.MongoDB.Tests/Serialization/Conventions/DateTimeOffsetRepresentationConventionTests.cs +++ b/tests/Tingle.Extensions.MongoDB.Tests/Serialization/Conventions/DateTimeOffsetRepresentationConventionTests.cs @@ -12,7 +12,7 @@ public class DateTimeOffsetRepresentationConventionTests [InlineData(BsonType.Document)] [InlineData(BsonType.DateTime)] [InlineData(BsonType.String)] - public void Convention_Is_Used_When_Memeber_Is_A_DateTimeOffset(BsonType representation) + public void Convention_Is_Used_When_Member_Is_A_DateTimeOffset(BsonType representation) { var subject = new DateTimeOffsetRepresentationConvention(representation); var classMap = new BsonClassMap(); @@ -29,7 +29,7 @@ public void Convention_Is_Used_When_Memeber_Is_A_DateTimeOffset(BsonType represe [InlineData(BsonType.Document)] [InlineData(BsonType.DateTime)] [InlineData(BsonType.String)] - public void Convention_Is_Used_When_Memeber_Is_A_Nullable_DateTimeOffset(BsonType representation) + public void Convention_Is_Used_When_Member_Is_A_Nullable_DateTimeOffset(BsonType representation) { var subject = new DateTimeOffsetRepresentationConvention(representation); var classMap = new BsonClassMap(); @@ -43,9 +43,9 @@ public void Convention_Is_Used_When_Memeber_Is_A_Nullable_DateTimeOffset(BsonTyp } [Fact] - public void Convention_Is_Not_Used_When_Memeber_Is_Not_A_DateTimeOffset() + public void Convention_Is_Not_Used_When_Member_Is_Not_A_DateTimeOffset() { - var subject = new DateTimeOffsetRepresentationConvention(BsonType.Array); + var subject = new DateTimeOffsetRepresentationConvention(BsonType.Document); var classMap = new BsonClassMap(); var memberMap = classMap.MapMember(b => b.Created); diff --git a/tests/Tingle.Extensions.MongoDB.Tests/Serialization/Serializers/EtagBsonSerializerTests.cs b/tests/Tingle.Extensions.MongoDB.Tests/Serialization/Serializers/EtagBsonSerializerTests.cs index 4b65732..f82bb90 100644 --- a/tests/Tingle.Extensions.MongoDB.Tests/Serialization/Serializers/EtagBsonSerializerTests.cs +++ b/tests/Tingle.Extensions.MongoDB.Tests/Serialization/Serializers/EtagBsonSerializerTests.cs @@ -52,7 +52,7 @@ public void Default_BsonRepresentation_IsUsed() Etag = new Etag(123456789UL) }; var json = obj.ToJson(); - var expected = $"{{ '_id' : 'cake', 'Etag' : NumberLong(123456789) }}".Replace("'", "\""); + var expected = $"{{ '_id' : 'cake', 'Etag' : 123456789 }}".Replace("'", "\""); Assert.Equal(expected, json); var bson = obj.ToBson(); @@ -63,8 +63,8 @@ public void Default_BsonRepresentation_IsUsed() [Theory] [InlineData(123456789UL, typeof(BookshopString), "'Fc1bBwAAAAA='")] - [InlineData(123456789UL, typeof(BookshopInt64), "NumberLong(123456789)")] - [InlineData(123456789UL, typeof(BookshopBinary), "new BinData(0, 'Fc1bBwAAAAA=')")] + [InlineData(123456789UL, typeof(BookshopInt64), "123456789")] + [InlineData(123456789UL, typeof(BookshopBinary), "{ '$binary' : { 'base64' : 'Fc1bBwAAAAA=', 'subType' : '00' } }")] public void BsonRepresentation_Is_Respected(ulong val, Type t, string bsonRaw) { var obj = (IBookshop)Activator.CreateInstance(t)!; diff --git a/tests/Tingle.Extensions.MongoDB.Tests/Serialization/Serializers/SequenceNumberBsonSerializerTests.cs b/tests/Tingle.Extensions.MongoDB.Tests/Serialization/Serializers/SequenceNumberBsonSerializerTests.cs index 994ac58..d9beb57 100644 --- a/tests/Tingle.Extensions.MongoDB.Tests/Serialization/Serializers/SequenceNumberBsonSerializerTests.cs +++ b/tests/Tingle.Extensions.MongoDB.Tests/Serialization/Serializers/SequenceNumberBsonSerializerTests.cs @@ -41,7 +41,7 @@ public void Default_BsonRepresentation_IsUsed() Position = new SequenceNumber(123456789) }; var json = obj.ToJson(); - var expected = $"{{ '_id' : 'cake', 'Position' : NumberLong(123456789) }}".Replace("'", "\""); + var expected = $"{{ '_id' : 'cake', 'Position' : 123456789 }}".Replace("'", "\""); Assert.Equal(expected, json); var bson = obj.ToBson(); @@ -52,7 +52,7 @@ public void Default_BsonRepresentation_IsUsed() [Theory] [InlineData(123456789UL, typeof(BookshopString), "'123456789'")] - [InlineData(123456789UL, typeof(BookshopInt64), "NumberLong(123456789)")] + [InlineData(123456789UL, typeof(BookshopInt64), "123456789")] public void BsonRepresentation_Is_Respected(long val, Type t, string bsonRaw) { var obj = (IBookshop)Activator.CreateInstance(t)!;