diff --git a/src/Prime.Extensions.Tests/FindFluentExtensionsTests.cs b/src/Prime.Extensions.Tests/FindFluentExtensionsTests.cs new file mode 100644 index 0000000..7eac942 --- /dev/null +++ b/src/Prime.Extensions.Tests/FindFluentExtensionsTests.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Text; +using MongoDB.Driver; +using Snapshooter.Xunit; +using Squadron; +using System.Threading.Tasks; +using Xunit; + +namespace MongoDB.Prime.Extensions.Tests +{ + public class FindFluentExtensionsTests : IClassFixture + { + private readonly IMongoDatabase _mongoDatabase; + + public FindFluentExtensionsTests(MongoResource mongoResource) + { + _mongoDatabase = mongoResource.CreateDatabase(); + } + + [Fact] + public void PrintQuery_PrintOneSingleQuery_OriginalMongoDbQueryPrinted() + { + // Arrange + IMongoCollection barCollection = + _mongoDatabase.GetCollection(); + + // Act + string mongodbQuery = barCollection + .Find(bar => bar.Name == "Bar1" || bar.Id == "1234") + .Limit(5) + .PrintQuery(); + + // Assert + Snapshot.Match(mongodbQuery); + } + } +} diff --git a/src/Prime.Extensions.Tests/Helpers/Bar.cs b/src/Prime.Extensions.Tests/Helpers/Bar.cs new file mode 100644 index 0000000..19cc1a9 --- /dev/null +++ b/src/Prime.Extensions.Tests/Helpers/Bar.cs @@ -0,0 +1,14 @@ +namespace MongoDB.Prime.Extensions.Tests +{ + public class Bar + { + public Bar(string name) + { + Name = name; + } + + public string Id { get; set; } + + public string Name { get; set; } + } +} diff --git a/src/Prime.Extensions.Tests/Helpers/Foo.cs b/src/Prime.Extensions.Tests/Helpers/Foo.cs new file mode 100644 index 0000000..66fa339 --- /dev/null +++ b/src/Prime.Extensions.Tests/Helpers/Foo.cs @@ -0,0 +1,13 @@ +namespace MongoDB.Prime.Extensions.Tests +{ + public class Foo + { + public Foo(string name) + { + Name = name; + } + + public string Id { get; set; } + public string Name { get; set; } + } +} diff --git a/src/Prime.Extensions.Tests/MongoCollectionExtensionsTests.cs b/src/Prime.Extensions.Tests/MongoCollectionExtensionsTests.cs new file mode 100644 index 0000000..0a55c98 --- /dev/null +++ b/src/Prime.Extensions.Tests/MongoCollectionExtensionsTests.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Text; +using MongoDB.Driver; +using Snapshooter.Xunit; +using Squadron; +using System.Threading.Tasks; +using Xunit; + +namespace MongoDB.Prime.Extensions.Tests +{ + public class MongoCollectionExtensionsTests : IClassFixture + { + private readonly IMongoDatabase _mongoDatabase; + + public MongoCollectionExtensionsTests(MongoResource mongoResource) + { + _mongoDatabase = mongoResource.CreateDatabase(); + } + + [Fact(Skip = "not ready yet.")] + public async Task Explain_ExplainSingleQuery_SuccessfullyExplained() + { + // Arrange + IMongoCollection barCollection = + _mongoDatabase.GetCollection(); + + FindOptions findOptions = new FindOptions + { + Collation = new Collation( + locale: "en", + strength: CollationStrength.Secondary) + }; + + FilterDefinition filter = + Builders.Filter.And( + Builders.Filter.Eq(u => u.Id, "1234"), + Builders.Filter.Eq(b => b.Name, "NN")); + + // Act + string? mongodbExplain = barCollection.Explain(filter, findOptions); + + // Assert + Snapshot.Match(mongodbExplain); + } + } +} diff --git a/src/Prime.Extensions.Tests/MongoCollectionFindExtensionsTests.cs b/src/Prime.Extensions.Tests/MongoCollectionFindExtensionsTests.cs index 764105c..54783be 100644 --- a/src/Prime.Extensions.Tests/MongoCollectionFindExtensionsTests.cs +++ b/src/Prime.Extensions.Tests/MongoCollectionFindExtensionsTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; @@ -11,11 +11,11 @@ namespace MongoDB.Prime.Extensions.Tests { - public class MongoCollectionExtensionsTests : IClassFixture + public class MongoCollectionFindExtensionsTests : IClassFixture { private readonly IMongoDatabase _mongoDatabase; - public MongoCollectionExtensionsTests(MongoResource mongoResource) + public MongoCollectionFindExtensionsTests(MongoResource mongoResource) { _mongoDatabase = mongoResource.CreateDatabase(); } @@ -623,4 +623,4 @@ public Bar(Guid id, string name, string value) #endregion } -} \ No newline at end of file +} diff --git a/src/Prime.Extensions.Tests/MongoDatabaseExtensionsTests.cs b/src/Prime.Extensions.Tests/MongoDatabaseExtensionsTests.cs index e6ce68a..ac8de62 100644 --- a/src/Prime.Extensions.Tests/MongoDatabaseExtensionsTests.cs +++ b/src/Prime.Extensions.Tests/MongoDatabaseExtensionsTests.cs @@ -1,5 +1,10 @@ -using MongoDB.Bson; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json; +using System.Text.Json.Nodes; +using MongoDB.Bson; using MongoDB.Driver; +using Snapshooter.Xunit; using Squadron; using Xunit; @@ -140,5 +145,77 @@ public void GetProfilingStatus_GetEnabledProfileStatusAll_StatusAll() } #endregion GetProfilingStatus Tests + + #region GetProfiledOperations Tests + + [Fact] + public void GetProfiledOperations_GetOneExecutedOperations_ReturnsOneMongoDBOperation() + { + // Arrange + _mongoDatabase.EnableProfiling(); + + _mongoDatabase.CreateCollection("Bar"); + + // Act + IEnumerable results = + _mongoDatabase.GetProfiledOperations(); + + // Assert + Snapshot.Match(results.Single(), + matchOptions => matchOptions + .IgnoreField("**.ns") + .IgnoreField("**.$db") + .IgnoreField("**.flowControl") + .IgnoreField("**.millis") + .IgnoreField("**.ts") + .IgnoreField("**.base64") + .IgnoreField("**.client") + .IgnoreField("**.locks") + .IgnoreField("**.ReplicationStateTransition") + .IgnoreField("**.FeatureCompatibilityVersion") + .IgnoreField("**.queryHash") + .IgnoreField("**.planCacheKey") + .IgnoreField("**.queryExecutionEngine") + .IgnoreField("**.readConcern") + ); + } + + [Fact] + public void GetProfiledOperations_GetAllExecutedOperations_ReturnsAllMongoDBOperations() + { + // Arrange + _mongoDatabase.EnableProfiling(); + + _mongoDatabase.CreateCollection("Bar"); + _mongoDatabase.CreateCollection("Foo"); + _mongoDatabase.GetCollection().InsertOne(new Bar("bar1")); + _mongoDatabase.GetCollection().InsertOne(new Foo("foo1")); + _mongoDatabase.GetCollection().Find(foo => foo.Name == "foo1").ToList(); + + // Act + string[] results = + _mongoDatabase.GetProfiledOperations().ToArray(); + + // Assert + Snapshot.Match(results.ToJsonArray(), + matchOptions => matchOptions + .IgnoreField("**.ns") + .IgnoreField("**.$db") + .IgnoreField("**.flowControl") + .IgnoreField("**.millis") + .IgnoreField("**.ts") + .IgnoreField("**.base64") + .IgnoreField("**.client") + .IgnoreField("**.locks") + .IgnoreField("**.ReplicationStateTransition") + .IgnoreField("**.FeatureCompatibilityVersion") + .IgnoreField("**.queryHash") + .IgnoreField("**.planCacheKey") + .IgnoreField("**.queryExecutionEngine") + .IgnoreField("**.readConcern") + ); + } + + #endregion } } diff --git a/src/Prime.Extensions.Tests/Prime.Extensions.Tests.csproj b/src/Prime.Extensions.Tests/Prime.Extensions.Tests.csproj index b412507..84ecd7d 100644 --- a/src/Prime.Extensions.Tests/Prime.Extensions.Tests.csproj +++ b/src/Prime.Extensions.Tests/Prime.Extensions.Tests.csproj @@ -10,4 +10,8 @@ + + + + diff --git a/src/Prime.Extensions.Tests/__snapshots__/FindFluentExtensionsTests.PrintQuery_PrintOneSingleQuery_OriginalMongoDbQueryPrinted.snap b/src/Prime.Extensions.Tests/__snapshots__/FindFluentExtensionsTests.PrintQuery_PrintOneSingleQuery_OriginalMongoDbQueryPrinted.snap new file mode 100644 index 0000000..5290c28 --- /dev/null +++ b/src/Prime.Extensions.Tests/__snapshots__/FindFluentExtensionsTests.PrintQuery_PrintOneSingleQuery_OriginalMongoDbQueryPrinted.snap @@ -0,0 +1 @@ +find({ "$or" : [{ "Name" : "Bar1" }, { "_id" : "1234" }] }).limit(5) diff --git a/src/Prime.Extensions.Tests/__snapshots__/MongoCollectionFindExtensionsTests.FindIds_FindDuplicatedBarIdsAsynchronously_ReturnsDistinctBars.snap b/src/Prime.Extensions.Tests/__snapshots__/MongoCollectionFindExtensionsTests.FindIds_FindDuplicatedBarIdsAsynchronously_ReturnsDistinctBars.snap new file mode 100644 index 0000000..da2e0f5 --- /dev/null +++ b/src/Prime.Extensions.Tests/__snapshots__/MongoCollectionFindExtensionsTests.FindIds_FindDuplicatedBarIdsAsynchronously_ReturnsDistinctBars.snap @@ -0,0 +1,34 @@ +[ + { + "Key": "a1c9e3e8-b448-42da-a684-716932903041", + "Value": { + "Id": "a1c9e3e8-b448-42da-a684-716932903041", + "Name": "Bar1", + "Value": "Value1" + } + }, + { + "Key": "a1c9e3e8-b448-42da-a684-716932903044", + "Value": { + "Id": "a1c9e3e8-b448-42da-a684-716932903044", + "Name": "Bar4", + "Value": "Value4" + } + }, + { + "Key": "a1c9e3e8-b448-42da-a684-716932903046", + "Value": { + "Id": "a1c9e3e8-b448-42da-a684-716932903046", + "Name": "Bar6", + "Value": "Value6" + } + }, + { + "Key": "a1c9e3e8-b448-42da-a684-716932903047", + "Value": { + "Id": "a1c9e3e8-b448-42da-a684-716932903047", + "Name": "Bar7", + "Value": "Value7" + } + } +] diff --git a/src/Prime.Extensions.Tests/__snapshots__/MongoCollectionFindExtensionsTests.FindIds_FindDuplicatedBarIdsSynchronously_ReturnsDistinctBars.snap b/src/Prime.Extensions.Tests/__snapshots__/MongoCollectionFindExtensionsTests.FindIds_FindDuplicatedBarIdsSynchronously_ReturnsDistinctBars.snap new file mode 100644 index 0000000..48fd5f4 --- /dev/null +++ b/src/Prime.Extensions.Tests/__snapshots__/MongoCollectionFindExtensionsTests.FindIds_FindDuplicatedBarIdsSynchronously_ReturnsDistinctBars.snap @@ -0,0 +1,26 @@ +[ + { + "Key": "a1c9e3e8-b448-42da-a684-716932903041", + "Value": { + "Id": "a1c9e3e8-b448-42da-a684-716932903041", + "Name": "Bar1", + "Value": "Value1" + } + }, + { + "Key": "a1c9e3e8-b448-42da-a684-716932903044", + "Value": { + "Id": "a1c9e3e8-b448-42da-a684-716932903044", + "Name": "Bar4", + "Value": "Value4" + } + }, + { + "Key": "a1c9e3e8-b448-42da-a684-716932903046", + "Value": { + "Id": "a1c9e3e8-b448-42da-a684-716932903046", + "Name": "Bar6", + "Value": "Value6" + } + } +] diff --git a/src/Prime.Extensions.Tests/__snapshots__/MongoCollectionFindExtensionsTests.FindIds_FindFourBarIdsAsynchronously_ReturnsRightBars.snap b/src/Prime.Extensions.Tests/__snapshots__/MongoCollectionFindExtensionsTests.FindIds_FindFourBarIdsAsynchronously_ReturnsRightBars.snap new file mode 100644 index 0000000..c528139 --- /dev/null +++ b/src/Prime.Extensions.Tests/__snapshots__/MongoCollectionFindExtensionsTests.FindIds_FindFourBarIdsAsynchronously_ReturnsRightBars.snap @@ -0,0 +1,34 @@ +[ + { + "Key": "a1c9e3e8-b448-42da-a684-716932903043", + "Value": { + "Id": "a1c9e3e8-b448-42da-a684-716932903043", + "Name": "Bar3", + "Value": "Value3" + } + }, + { + "Key": "a1c9e3e8-b448-42da-a684-716932903044", + "Value": { + "Id": "a1c9e3e8-b448-42da-a684-716932903044", + "Name": "Bar4", + "Value": "Value4" + } + }, + { + "Key": "a1c9e3e8-b448-42da-a684-716932903045", + "Value": { + "Id": "a1c9e3e8-b448-42da-a684-716932903045", + "Name": "Bar5", + "Value": "Value5" + } + }, + { + "Key": "a1c9e3e8-b448-42da-a684-716932903046", + "Value": { + "Id": "a1c9e3e8-b448-42da-a684-716932903046", + "Name": "Bar6", + "Value": "Value6" + } + } +] diff --git a/src/Prime.Extensions.Tests/__snapshots__/MongoCollectionFindExtensionsTests.FindIds_FindFourBarIdsSynchronously_ReturnsRightBars.snap b/src/Prime.Extensions.Tests/__snapshots__/MongoCollectionFindExtensionsTests.FindIds_FindFourBarIdsSynchronously_ReturnsRightBars.snap new file mode 100644 index 0000000..c528139 --- /dev/null +++ b/src/Prime.Extensions.Tests/__snapshots__/MongoCollectionFindExtensionsTests.FindIds_FindFourBarIdsSynchronously_ReturnsRightBars.snap @@ -0,0 +1,34 @@ +[ + { + "Key": "a1c9e3e8-b448-42da-a684-716932903043", + "Value": { + "Id": "a1c9e3e8-b448-42da-a684-716932903043", + "Name": "Bar3", + "Value": "Value3" + } + }, + { + "Key": "a1c9e3e8-b448-42da-a684-716932903044", + "Value": { + "Id": "a1c9e3e8-b448-42da-a684-716932903044", + "Name": "Bar4", + "Value": "Value4" + } + }, + { + "Key": "a1c9e3e8-b448-42da-a684-716932903045", + "Value": { + "Id": "a1c9e3e8-b448-42da-a684-716932903045", + "Name": "Bar5", + "Value": "Value5" + } + }, + { + "Key": "a1c9e3e8-b448-42da-a684-716932903046", + "Value": { + "Id": "a1c9e3e8-b448-42da-a684-716932903046", + "Name": "Bar6", + "Value": "Value6" + } + } +] diff --git a/src/Prime.Extensions.Tests/__snapshots__/MongoCollectionFindExtensionsTests.FindIds_FindFourBarNamesAsynchronously_ReturnsRightBars.snap b/src/Prime.Extensions.Tests/__snapshots__/MongoCollectionFindExtensionsTests.FindIds_FindFourBarNamesAsynchronously_ReturnsRightBars.snap new file mode 100644 index 0000000..400e9ed --- /dev/null +++ b/src/Prime.Extensions.Tests/__snapshots__/MongoCollectionFindExtensionsTests.FindIds_FindFourBarNamesAsynchronously_ReturnsRightBars.snap @@ -0,0 +1,34 @@ +[ + { + "Key": "Bar3", + "Value": { + "Id": "a1c9e3e8-b448-42da-a684-716932903043", + "Name": "Bar3", + "Value": "Value3" + } + }, + { + "Key": "Bar4", + "Value": { + "Id": "a1c9e3e8-b448-42da-a684-716932903044", + "Name": "Bar4", + "Value": "Value4" + } + }, + { + "Key": "Bar5", + "Value": { + "Id": "a1c9e3e8-b448-42da-a684-716932903045", + "Name": "Bar5", + "Value": "Value5" + } + }, + { + "Key": "Bar6", + "Value": { + "Id": "a1c9e3e8-b448-42da-a684-716932903046", + "Name": "Bar6", + "Value": "Value6" + } + } +] diff --git a/src/Prime.Extensions.Tests/__snapshots__/MongoCollectionFindExtensionsTests.FindIds_FindFourBarNamesSynchronously_ReturnsRightBars.snap b/src/Prime.Extensions.Tests/__snapshots__/MongoCollectionFindExtensionsTests.FindIds_FindFourBarNamesSynchronously_ReturnsRightBars.snap new file mode 100644 index 0000000..400e9ed --- /dev/null +++ b/src/Prime.Extensions.Tests/__snapshots__/MongoCollectionFindExtensionsTests.FindIds_FindFourBarNamesSynchronously_ReturnsRightBars.snap @@ -0,0 +1,34 @@ +[ + { + "Key": "Bar3", + "Value": { + "Id": "a1c9e3e8-b448-42da-a684-716932903043", + "Name": "Bar3", + "Value": "Value3" + } + }, + { + "Key": "Bar4", + "Value": { + "Id": "a1c9e3e8-b448-42da-a684-716932903044", + "Name": "Bar4", + "Value": "Value4" + } + }, + { + "Key": "Bar5", + "Value": { + "Id": "a1c9e3e8-b448-42da-a684-716932903045", + "Name": "Bar5", + "Value": "Value5" + } + }, + { + "Key": "Bar6", + "Value": { + "Id": "a1c9e3e8-b448-42da-a684-716932903046", + "Name": "Bar6", + "Value": "Value6" + } + } +] diff --git a/src/Prime.Extensions.Tests/__snapshots__/MongoCollectionFindExtensionsTests.FindIds_FindOneId_ReturnsRightBar.snap b/src/Prime.Extensions.Tests/__snapshots__/MongoCollectionFindExtensionsTests.FindIds_FindOneId_ReturnsRightBar.snap new file mode 100644 index 0000000..08ed536 --- /dev/null +++ b/src/Prime.Extensions.Tests/__snapshots__/MongoCollectionFindExtensionsTests.FindIds_FindOneId_ReturnsRightBar.snap @@ -0,0 +1,7 @@ +{ + "a1c9e3e8-b448-42da-a684-716932903043": { + "Id": "a1c9e3e8-b448-42da-a684-716932903043", + "Name": "Bar1", + "Value": "Value1" + } +} diff --git a/src/Prime.Extensions.Tests/__snapshots__/MongoDatabaseExtensionsTests.GetProfiledOperations_GetAllExecutedOperations_ReturnsAllMongoDBOperations.snap b/src/Prime.Extensions.Tests/__snapshots__/MongoDatabaseExtensionsTests.GetProfiledOperations_GetAllExecutedOperations_ReturnsAllMongoDBOperations.snap new file mode 100644 index 0000000..b9a8b5d --- /dev/null +++ b/src/Prime.Extensions.Tests/__snapshots__/MongoDatabaseExtensionsTests.GetProfiledOperations_GetAllExecutedOperations_ReturnsAllMongoDBOperations.snap @@ -0,0 +1,329 @@ +[{ + "op": "command", + "ns": "db_98188f7406cc40a888db9ab8056eb396.Bar", + "command": { + "create": "Bar", + "$db": "db_98188f7406cc40a888db9ab8056eb396", + "lsid": { + "id": { + "$binary": { + "base64": "w6P\u002BgezU1ECJmuzdA0rhPg==", + "subType": "03" + } + } + } + }, + "numYield": 0, + "locks": { + "ParallelBatchWriterMode": { + "acquireCount": { + "r": 2 + } + }, + "ReplicationStateTransition": { + "acquireCount": { + "w": 2 + } + }, + "Global": { + "acquireCount": { + "r": 1, + "w": 1 + } + }, + "Database": { + "acquireCount": { + "r": 1, + "w": 1 + } + }, + "Collection": { + "acquireCount": { + "w": 1 + } + }, + "Mutex": { + "acquireCount": { + "r": 2 + } + } + }, + "flowControl": { + "acquireCount": 1, + "timeAcquiringMicros": 5 + }, + "responseLength": 38, + "protocol": "op_msg", + "millis": 18, + "ts": { + "$date": "2022-10-24T12:34:51.893Z" + }, + "client": "172.17.0.1", + "allUsers": [], + "user": "" +},{ + "op": "command", + "ns": "db_98188f7406cc40a888db9ab8056eb396.Foo", + "command": { + "create": "Foo", + "$db": "db_98188f7406cc40a888db9ab8056eb396", + "lsid": { + "id": { + "$binary": { + "base64": "w6P\u002BgezU1ECJmuzdA0rhPg==", + "subType": "03" + } + } + } + }, + "numYield": 0, + "locks": { + "ParallelBatchWriterMode": { + "acquireCount": { + "r": 2 + } + }, + "ReplicationStateTransition": { + "acquireCount": { + "w": 2 + } + }, + "Global": { + "acquireCount": { + "r": 1, + "w": 1 + } + }, + "Database": { + "acquireCount": { + "r": 1, + "w": 1 + } + }, + "Collection": { + "acquireCount": { + "w": 1 + } + }, + "Mutex": { + "acquireCount": { + "r": 2 + } + } + }, + "flowControl": { + "acquireCount": 1, + "timeAcquiringMicros": 4 + }, + "responseLength": 38, + "protocol": "op_msg", + "millis": 16, + "ts": { + "$date": "2022-10-24T12:34:51.921Z" + }, + "client": "172.17.0.1", + "allUsers": [], + "user": "" +},{ + "op": "insert", + "ns": "db_98188f7406cc40a888db9ab8056eb396.Bar", + "command": { + "insert": "Bar", + "ordered": true, + "$db": "db_98188f7406cc40a888db9ab8056eb396", + "lsid": { + "id": { + "$binary": { + "base64": "w6P\u002BgezU1ECJmuzdA0rhPg==", + "subType": "03" + } + } + } + }, + "ninserted": 1, + "keysInserted": 1, + "numYield": 0, + "locks": { + "ParallelBatchWriterMode": { + "acquireCount": { + "r": 1 + } + }, + "ReplicationStateTransition": { + "acquireCount": { + "w": 1 + } + }, + "Global": { + "acquireCount": { + "w": 1 + } + }, + "Database": { + "acquireCount": { + "w": 1 + } + }, + "Collection": { + "acquireCount": { + "w": 1 + } + }, + "Mutex": { + "acquireCount": { + "r": 1 + } + } + }, + "flowControl": { + "acquireCount": 1, + "timeAcquiringMicros": 5 + }, + "responseLength": 45, + "protocol": "op_msg", + "millis": 0, + "ts": { + "$date": "2022-10-24T12:34:52.026Z" + }, + "client": "172.17.0.1", + "allUsers": [], + "user": "" +},{ + "op": "insert", + "ns": "db_98188f7406cc40a888db9ab8056eb396.Foo", + "command": { + "insert": "Foo", + "ordered": true, + "$db": "db_98188f7406cc40a888db9ab8056eb396", + "lsid": { + "id": { + "$binary": { + "base64": "w6P\u002BgezU1ECJmuzdA0rhPg==", + "subType": "03" + } + } + } + }, + "ninserted": 1, + "keysInserted": 1, + "numYield": 0, + "locks": { + "ParallelBatchWriterMode": { + "acquireCount": { + "r": 1 + } + }, + "ReplicationStateTransition": { + "acquireCount": { + "w": 1 + } + }, + "Global": { + "acquireCount": { + "w": 1 + } + }, + "Database": { + "acquireCount": { + "w": 1 + } + }, + "Collection": { + "acquireCount": { + "w": 1 + } + }, + "Mutex": { + "acquireCount": { + "r": 1 + } + } + }, + "flowControl": { + "acquireCount": 1, + "timeAcquiringMicros": 4 + }, + "responseLength": 45, + "protocol": "op_msg", + "millis": 0, + "ts": { + "$date": "2022-10-24T12:34:52.041Z" + }, + "client": "172.17.0.1", + "allUsers": [], + "user": "" +},{ + "op": "query", + "ns": "db_98188f7406cc40a888db9ab8056eb396.Foo", + "command": { + "find": "Foo", + "filter": { + "Name": "foo1" + }, + "readConcern": { + "level": "majority" + }, + "$db": "db_98188f7406cc40a888db9ab8056eb396", + "lsid": { + "id": { + "$binary": { + "base64": "w6P\u002BgezU1ECJmuzdA0rhPg==", + "subType": "03" + } + } + } + }, + "keysExamined": 0, + "docsExamined": 1, + "cursorExhausted": true, + "numYield": 0, + "nreturned": 1, + "queryHash": "EBFEE4C5", + "planCacheKey": "CEC3A330", + "locks": { + "Global": { + "acquireCount": { + "r": 1 + } + }, + "Mutex": { + "acquireCount": { + "r": 1 + } + } + }, + "flowControl": {}, + "readConcern": { + "level": "majority", + "provenance": "clientSupplied" + }, + "responseLength": 156, + "protocol": "op_msg", + "millis": 0, + "planSummary": "COLLSCAN", + "execStats": { + "stage": "COLLSCAN", + "filter": { + "Name": { + "$eq": "foo1" + } + }, + "nReturned": 1, + "executionTimeMillisEstimate": 0, + "works": 3, + "advanced": 1, + "needTime": 1, + "needYield": 0, + "saveState": 0, + "restoreState": 0, + "isEOF": 1, + "direction": "forward", + "docsExamined": 1 + }, + "ts": { + "$date": "2022-10-24T12:34:52.088Z" + }, + "client": "172.17.0.1", + "allUsers": [], + "user": "" +}] diff --git a/src/Prime.Extensions.Tests/__snapshots__/MongoDatabaseExtensionsTests.GetProfiledOperations_GetOneExecutedOperations_ReturnsOneMongoDBOperation.snap b/src/Prime.Extensions.Tests/__snapshots__/MongoDatabaseExtensionsTests.GetProfiledOperations_GetOneExecutedOperations_ReturnsOneMongoDBOperation.snap new file mode 100644 index 0000000..cba0c00 --- /dev/null +++ b/src/Prime.Extensions.Tests/__snapshots__/MongoDatabaseExtensionsTests.GetProfiledOperations_GetOneExecutedOperations_ReturnsOneMongoDBOperation.snap @@ -0,0 +1,64 @@ +{ + "op": "command", + "ns": "db_2073f5d0f83849bb991287c1b488d141.Bar", + "command": { + "create": "Bar", + "$db": "db_2073f5d0f83849bb991287c1b488d141", + "lsid": { + "id": { + "$binary": { + "base64": "LS6ugmsi2EiKMKvM62WMng==", + "subType": "03" + } + } + } + }, + "numYield": 0, + "locks": { + "ParallelBatchWriterMode": { + "acquireCount": { + "r": 2 + } + }, + "ReplicationStateTransition": { + "acquireCount": { + "w": 2 + } + }, + "Global": { + "acquireCount": { + "r": 1, + "w": 1 + } + }, + "Database": { + "acquireCount": { + "r": 1, + "w": 1 + } + }, + "Collection": { + "acquireCount": { + "w": 1 + } + }, + "Mutex": { + "acquireCount": { + "r": 2 + } + } + }, + "flowControl": { + "acquireCount": 1, + "timeAcquiringMicros": 3 + }, + "responseLength": 38, + "protocol": "op_msg", + "millis": 17, + "ts": { + "$date": "2022-10-24T12:44:09.669Z" + }, + "client": "172.17.0.1", + "allUsers": [], + "user": "" +} diff --git a/src/Prime.Extensions/FindFluentExtensions.cs b/src/Prime.Extensions/FindFluentExtensions.cs new file mode 100644 index 0000000..e911c06 --- /dev/null +++ b/src/Prime.Extensions/FindFluentExtensions.cs @@ -0,0 +1,13 @@ +using MongoDB.Driver; + +namespace MongoDB.Prime.Extensions +{ + public static class FindFluentExtensions + { + public static string PrintQuery( + this IFindFluent findFluent) + { + return findFluent.ToString(); + } + } +} diff --git a/src/Prime.Extensions/MongoCollectionExtensions.cs b/src/Prime.Extensions/MongoCollectionExtensions.cs index a773697..a89f3cf 100644 --- a/src/Prime.Extensions/MongoCollectionExtensions.cs +++ b/src/Prime.Extensions/MongoCollectionExtensions.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using MongoDB.Bson; using MongoDB.Driver; namespace MongoDB.Prime.Extensions @@ -40,5 +41,34 @@ public static Task InsertManyAsync( return collection.InsertManyAsync( documents, options, cancellationToken); } + + public static string? Explain( + this IMongoCollection collection, + FilterDefinition filter) + { + var options = new FindOptions + { + Modifiers = new BsonDocument("$explain", true) + }; + + return Explain(collection, filter, options); + } + + public static string? Explain( + this IMongoCollection collection, + FilterDefinition filter, + FindOptions findOptions) + { + findOptions.Modifiers = + new BsonDocument("$explain", true); + + string? explain = collection + .Find(filter, findOptions) + .Project(new BsonDocument()) + .FirstOrDefault() + ?.ToJson(); + + return explain; + } } } diff --git a/src/Prime.Extensions/MongoDatabaseExtensions.cs b/src/Prime.Extensions/MongoDatabaseExtensions.cs index 467cd9d..17012f1 100644 --- a/src/Prime.Extensions/MongoDatabaseExtensions.cs +++ b/src/Prime.Extensions/MongoDatabaseExtensions.cs @@ -1,5 +1,9 @@ -using System; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json; using MongoDB.Bson; +using MongoDB.Bson.IO; using MongoDB.Driver; namespace MongoDB.Prime.Extensions @@ -15,7 +19,8 @@ public static void EnableProfiling( mongoDatabase.RunCommand(profileCommand); } - public static ProfilingStatus GetProfilingStatus(this IMongoDatabase mongoDatabase) + public static ProfilingStatus GetProfilingStatus( + this IMongoDatabase mongoDatabase) { var profileStatusCommand = new BsonDocument("profile", -1); @@ -25,7 +30,8 @@ public static ProfilingStatus GetProfilingStatus(this IMongoDatabase mongoDataba return CreateProfilingStatus(profileBsonDocument); } - private static ProfilingStatus CreateProfilingStatus(BsonDocument profileBsonDocument) + private static ProfilingStatus CreateProfilingStatus( + BsonDocument profileBsonDocument) { return new ProfilingStatus( level: (ProfileLevel)profileBsonDocument["was"].AsInt32, @@ -34,11 +40,40 @@ private static ProfilingStatus CreateProfilingStatus(BsonDocument profileBsonDoc filter: profileBsonDocument["ok"].AsDouble.ToString()); } + public static IEnumerable GetProfiledOperations( + this IMongoDatabase mongoDatabase) + { + IMongoCollection collection = mongoDatabase + .GetCollection("system.profile"); + + List docs = collection + .Find(new BsonDocument()) + .ToList(); + + IEnumerable jsons = docs.Select(bson => bson.ToJson( + new JsonWriterSettings + { + OutputMode = JsonOutputMode.RelaxedExtendedJson + })); + + IEnumerable normalizedJson = jsons + .Select(json => JsonSerializer + .Serialize( + JsonDocument.Parse(json).RootElement, + new JsonSerializerOptions() + { + WriteIndented = true + })); + + return normalizedJson; + } + public static IMongoCollection GetCollection( this IMongoDatabase mongoDatabase, MongoCollectionSettings? settings = null) { - return mongoDatabase.GetCollection(typeof(TDocument).Name, settings); + return mongoDatabase + .GetCollection(typeof(TDocument).Name, settings); } } } diff --git a/src/Prime.Extensions/Prime.Extensions.csproj b/src/Prime.Extensions/Prime.Extensions.csproj index 005a658..012c42f 100644 --- a/src/Prime.Extensions/Prime.Extensions.csproj +++ b/src/Prime.Extensions/Prime.Extensions.csproj @@ -9,6 +9,7 @@ + diff --git a/src/Prime.Extensions/StringExtensions.cs b/src/Prime.Extensions/StringExtensions.cs new file mode 100644 index 0000000..175efec --- /dev/null +++ b/src/Prime.Extensions/StringExtensions.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json; + +namespace MongoDB.Prime.Extensions +{ + public static class StringExtensions + { + public static string ToJsonArray(this IEnumerable jsonArray) + { + return string.Concat("[", string.Join(",", jsonArray), "]"); + } + } +}