diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9a41ec17..c87d58d8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,15 +21,6 @@ jobs: steps: - name: Checkout Repository uses: actions/checkout@v3 - - name: Start Redis - uses: supercharge/redis-github-action@1.2.0 - with: - redis-version: 7.0.2 - - name: Start MongoDB - uses: supercharge/mongodb-github-action@1.7.0 - with: - mongodb-version: 5.0.9 - mongodb-replica-set: entitydb - name: Install .NET SDK uses: actions/setup-dotnet@v2 - name: Restore Dependencies diff --git a/.github/workflows/publish-beta.yml b/.github/workflows/publish-beta.yml index feaf9369..a79a0b36 100644 --- a/.github/workflows/publish-beta.yml +++ b/.github/workflows/publish-beta.yml @@ -37,15 +37,6 @@ jobs: steps: - name: Checkout Repository uses: actions/checkout@v3 - - name: Start Redis - uses: supercharge/redis-github-action@1.2.0 - with: - redis-version: 7.0.2 - - name: Start MongoDB - uses: supercharge/mongodb-github-action@1.7.0 - with: - mongodb-version: 5.0.9 - mongodb-replica-set: entitydb - name: Install .NET SDK uses: actions/setup-dotnet@v2 - name: Restore Dependencies diff --git a/.github/workflows/publish-stable.yml b/.github/workflows/publish-stable.yml index e60153af..15fe4284 100644 --- a/.github/workflows/publish-stable.yml +++ b/.github/workflows/publish-stable.yml @@ -45,15 +45,6 @@ jobs: steps: - name: Checkout Repository uses: actions/checkout@v3 - - name: Start Redis - uses: supercharge/redis-github-action@1.2.0 - with: - redis-version: 7.0.2 - - name: Start MongoDB - uses: supercharge/mongodb-github-action@1.7.0 - with: - mongodb-version: 5.0.9 - mongodb-replica-set: entitydb - name: Install .NET SDK uses: actions/setup-dotnet@v2 - name: Restore Dependencies diff --git a/Directory.Build.props b/Directory.Build.props index e1913bdd..026d3c98 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -5,5 +5,10 @@ 10.0 enable True + enable + + + + \ No newline at end of file diff --git a/EntityDb.sln b/EntityDb.sln index 4ff658ab..317a0623 100644 --- a/EntityDb.sln +++ b/EntityDb.sln @@ -25,7 +25,6 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{92484C44-2754-4C1D-BD46-98D83E4020EE}" ProjectSection(SolutionItems) = preProject test\Directory.Build.props = test\Directory.Build.props - test\docker-compose.yml = test\docker-compose.yml EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EntityDb.Common.Tests", "test\EntityDb.Common.Tests\EntityDb.Common.Tests.csproj", "{CF316519-525E-4A67-BF12-1FDDF802B878}" @@ -42,7 +41,15 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution global.json = global.json EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EntityDb.InMemory", "src\EntityDb.InMemory\EntityDb.InMemory.csproj", "{31C5BEDB-9B04-4FE4-9AF5-AE682C0E7643}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EntityDb.InMemory", "src\EntityDb.InMemory\EntityDb.InMemory.csproj", "{31C5BEDB-9B04-4FE4-9AF5-AE682C0E7643}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EntityDb.Npgsql", "src\EntityDb.Npgsql\EntityDb.Npgsql.csproj", "{2AADF21D-4F26-4BD6-852A-B28208863FDD}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EntityDb.Npgsql.Provisioner", "src\EntityDb.Npgsql.Provisioner\EntityDb.Npgsql.Provisioner.csproj", "{282DFD9B-14E4-4339-B55A-3567E128FF1B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EntityDb.SqlDb", "src\EntityDb.SqlDb\EntityDb.SqlDb.csproj", "{F2491666-31D1-47B5-A493-F25E167D1FDF}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EntityDb.Json", "src\EntityDb.Json\EntityDb.Json.csproj", "{4936FFE0-98E5-43A2-89C9-0415A13CAA9B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -98,6 +105,22 @@ Global {31C5BEDB-9B04-4FE4-9AF5-AE682C0E7643}.Debug|Any CPU.Build.0 = Debug|Any CPU {31C5BEDB-9B04-4FE4-9AF5-AE682C0E7643}.Release|Any CPU.ActiveCfg = Release|Any CPU {31C5BEDB-9B04-4FE4-9AF5-AE682C0E7643}.Release|Any CPU.Build.0 = Release|Any CPU + {2AADF21D-4F26-4BD6-852A-B28208863FDD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2AADF21D-4F26-4BD6-852A-B28208863FDD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2AADF21D-4F26-4BD6-852A-B28208863FDD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2AADF21D-4F26-4BD6-852A-B28208863FDD}.Release|Any CPU.Build.0 = Release|Any CPU + {282DFD9B-14E4-4339-B55A-3567E128FF1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {282DFD9B-14E4-4339-B55A-3567E128FF1B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {282DFD9B-14E4-4339-B55A-3567E128FF1B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {282DFD9B-14E4-4339-B55A-3567E128FF1B}.Release|Any CPU.Build.0 = Release|Any CPU + {F2491666-31D1-47B5-A493-F25E167D1FDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F2491666-31D1-47B5-A493-F25E167D1FDF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F2491666-31D1-47B5-A493-F25E167D1FDF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F2491666-31D1-47B5-A493-F25E167D1FDF}.Release|Any CPU.Build.0 = Release|Any CPU + {4936FFE0-98E5-43A2-89C9-0415A13CAA9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4936FFE0-98E5-43A2-89C9-0415A13CAA9B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4936FFE0-98E5-43A2-89C9-0415A13CAA9B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4936FFE0-98E5-43A2-89C9-0415A13CAA9B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -115,6 +138,10 @@ Global {B8B6E5A5-5154-4629-9A38-9F0E65575F30} = {92484C44-2754-4C1D-BD46-98D83E4020EE} {FA2AD2E9-84DA-4667-BF46-140B0B050563} = {92484C44-2754-4C1D-BD46-98D83E4020EE} {31C5BEDB-9B04-4FE4-9AF5-AE682C0E7643} = {ABACFBCC-B59F-4616-B6CC-99C37AEC8960} + {2AADF21D-4F26-4BD6-852A-B28208863FDD} = {ABACFBCC-B59F-4616-B6CC-99C37AEC8960} + {282DFD9B-14E4-4339-B55A-3567E128FF1B} = {ABACFBCC-B59F-4616-B6CC-99C37AEC8960} + {F2491666-31D1-47B5-A493-F25E167D1FDF} = {ABACFBCC-B59F-4616-B6CC-99C37AEC8960} + {4936FFE0-98E5-43A2-89C9-0415A13CAA9B} = {ABACFBCC-B59F-4616-B6CC-99C37AEC8960} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E9D288EE-9351-4018-ABE8-B0968AEB0465} diff --git a/src/EntityDb.Abstractions/Agents/IAgentAccessor.cs b/src/EntityDb.Abstractions/Agents/IAgentAccessor.cs index 3aa1cc3c..a0bf7fbf 100644 --- a/src/EntityDb.Abstractions/Agents/IAgentAccessor.cs +++ b/src/EntityDb.Abstractions/Agents/IAgentAccessor.cs @@ -1,7 +1,4 @@ -using System.Threading; -using System.Threading.Tasks; - -namespace EntityDb.Abstractions.Agents; +namespace EntityDb.Abstractions.Agents; /// /// Represents a type that can access an instance of . diff --git a/src/EntityDb.Abstractions/Agents/IAgentSignatureAugmenter.cs b/src/EntityDb.Abstractions/Agents/IAgentSignatureAugmenter.cs index 976b2b86..3c3ff651 100644 --- a/src/EntityDb.Abstractions/Agents/IAgentSignatureAugmenter.cs +++ b/src/EntityDb.Abstractions/Agents/IAgentSignatureAugmenter.cs @@ -1,7 +1,3 @@ -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; - namespace EntityDb.Abstractions.Agents; /// diff --git a/src/EntityDb.Abstractions/Disposables/IDisposableResource.cs b/src/EntityDb.Abstractions/Disposables/IDisposableResource.cs index 6ac72b6a..d5862de8 100644 --- a/src/EntityDb.Abstractions/Disposables/IDisposableResource.cs +++ b/src/EntityDb.Abstractions/Disposables/IDisposableResource.cs @@ -1,6 +1,4 @@ -using System; - -namespace EntityDb.Abstractions.Disposables; +namespace EntityDb.Abstractions.Disposables; /// /// Marks a resource as disposable and provides a default implementation. diff --git a/src/EntityDb.Abstractions/Entities/IEntityRepository.cs b/src/EntityDb.Abstractions/Entities/IEntityRepository.cs index 65b774a4..1af25d9b 100644 --- a/src/EntityDb.Abstractions/Entities/IEntityRepository.cs +++ b/src/EntityDb.Abstractions/Entities/IEntityRepository.cs @@ -2,10 +2,7 @@ using EntityDb.Abstractions.Snapshots; using EntityDb.Abstractions.Transactions; using EntityDb.Abstractions.ValueObjects; -using System; using System.Diagnostics.CodeAnalysis; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.Abstractions.Entities; diff --git a/src/EntityDb.Abstractions/Entities/IEntityRepositoryFactory.cs b/src/EntityDb.Abstractions/Entities/IEntityRepositoryFactory.cs index 582806d4..975863b1 100644 --- a/src/EntityDb.Abstractions/Entities/IEntityRepositoryFactory.cs +++ b/src/EntityDb.Abstractions/Entities/IEntityRepositoryFactory.cs @@ -1,6 +1,3 @@ -using System.Threading; -using System.Threading.Tasks; - namespace EntityDb.Abstractions.Entities; /// diff --git a/src/EntityDb.Abstractions/Projections/IProjectionRepository.cs b/src/EntityDb.Abstractions/Projections/IProjectionRepository.cs index a1e76b8a..8d2018d1 100644 --- a/src/EntityDb.Abstractions/Projections/IProjectionRepository.cs +++ b/src/EntityDb.Abstractions/Projections/IProjectionRepository.cs @@ -2,10 +2,7 @@ using EntityDb.Abstractions.Snapshots; using EntityDb.Abstractions.Transactions; using EntityDb.Abstractions.ValueObjects; -using System; using System.Diagnostics.CodeAnalysis; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.Abstractions.Projections; diff --git a/src/EntityDb.Abstractions/Projections/IProjectionRepositoryFactory.cs b/src/EntityDb.Abstractions/Projections/IProjectionRepositoryFactory.cs index 1b25c753..a12c6502 100644 --- a/src/EntityDb.Abstractions/Projections/IProjectionRepositoryFactory.cs +++ b/src/EntityDb.Abstractions/Projections/IProjectionRepositoryFactory.cs @@ -1,6 +1,3 @@ -using System.Threading; -using System.Threading.Tasks; - namespace EntityDb.Abstractions.Projections; /// diff --git a/src/EntityDb.Abstractions/Queries/FilterBuilders/IAgentSignatureFilterBuilder.cs b/src/EntityDb.Abstractions/Queries/FilterBuilders/IAgentSignatureFilterBuilder.cs index f328d187..af4fa3cb 100644 --- a/src/EntityDb.Abstractions/Queries/FilterBuilders/IAgentSignatureFilterBuilder.cs +++ b/src/EntityDb.Abstractions/Queries/FilterBuilders/IAgentSignatureFilterBuilder.cs @@ -1,5 +1,5 @@ using EntityDb.Abstractions.ValueObjects; -using System; +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; namespace EntityDb.Abstractions.Queries.FilterBuilders; @@ -10,6 +10,12 @@ namespace EntityDb.Abstractions.Queries.FilterBuilders; /// The type of filter used by the repository. public interface IAgentSignatureFilterBuilder : IFilterBuilder { + /// + [Obsolete("This method will be removed in the future, and may not be supported for all implementations.")] + [ExcludeFromCodeCoverage(Justification = "Obsolete")] + TFilter AgentSignatureMatches(Expression> agentSignatureExpression) + => throw new NotSupportedException(); + /// /// Returns a that only includes agentSignatures with any entity id which is contained /// in a set @@ -33,16 +39,4 @@ public interface IAgentSignatureFilterBuilder : IFilterBuilder /// . /// TFilter AgentSignatureTypeIn(params Type[] agentSignatureTypes); - - /// - /// Returns a that only includes agentSignatures which do match a agentSignature - /// expression. - /// - /// The type of agentSignature in the agentSignature expression. - /// The agentSignature expression. - /// - /// A that only includes agentSignatures which do match - /// . - /// - TFilter AgentSignatureMatches(Expression> agentSignatureExpression); } diff --git a/src/EntityDb.Abstractions/Queries/FilterBuilders/ICommandFilterBuilder.cs b/src/EntityDb.Abstractions/Queries/FilterBuilders/ICommandFilterBuilder.cs index a1f48d63..9b5d2e5a 100644 --- a/src/EntityDb.Abstractions/Queries/FilterBuilders/ICommandFilterBuilder.cs +++ b/src/EntityDb.Abstractions/Queries/FilterBuilders/ICommandFilterBuilder.cs @@ -1,5 +1,5 @@ using EntityDb.Abstractions.ValueObjects; -using System; +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; namespace EntityDb.Abstractions.Queries.FilterBuilders; @@ -10,6 +10,12 @@ namespace EntityDb.Abstractions.Queries.FilterBuilders; /// The type of filter used by the repository. public interface ICommandFilterBuilder : IFilterBuilder { + /// + [Obsolete("This method will be removed in the future, and may not be supported for all implementations.")] + [ExcludeFromCodeCoverage(Justification = "Obsolete")] + TFilter CommandMatches(Expression> commandExpression) + => throw new NotSupportedException(); + /// /// Returns a that only includes commands with an entity id which is contained in a set /// of entity ids. @@ -53,15 +59,4 @@ public interface ICommandFilterBuilder : IFilterBuilder /// . /// TFilter CommandTypeIn(params Type[] commandTypes); - - /// - /// Returns a that only includes commands which do match a command expression. - /// - /// The type of command in the command expression. - /// The command expression. - /// - /// A that only includes commands which do match - /// . - /// - TFilter CommandMatches(Expression> commandExpression); } diff --git a/src/EntityDb.Abstractions/Queries/FilterBuilders/ILeaseFilterBuilder.cs b/src/EntityDb.Abstractions/Queries/FilterBuilders/ILeaseFilterBuilder.cs index 6ee6bc36..86c06086 100644 --- a/src/EntityDb.Abstractions/Queries/FilterBuilders/ILeaseFilterBuilder.cs +++ b/src/EntityDb.Abstractions/Queries/FilterBuilders/ILeaseFilterBuilder.cs @@ -1,5 +1,6 @@ -using EntityDb.Abstractions.ValueObjects; -using System; +using EntityDb.Abstractions.Leases; +using EntityDb.Abstractions.ValueObjects; +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; namespace EntityDb.Abstractions.Queries.FilterBuilders; @@ -10,6 +11,12 @@ namespace EntityDb.Abstractions.Queries.FilterBuilders; /// The type of filter used by the repository. public interface ILeaseFilterBuilder : IFilterBuilder { + /// + [Obsolete("This method will be removed in the future.")] + [ExcludeFromCodeCoverage(Justification = "Obsolete")] + TFilter LeaseMatches(Expression> leaseExpression) + => throw new NotSupportedException(); + /// /// Returns a that only includes leases with an entity id which is contained in a set /// of entity ids. @@ -55,13 +62,35 @@ public interface ILeaseFilterBuilder : IFilterBuilder TFilter LeaseTypeIn(params Type[] leaseTypes); /// - /// Returns a that only includes leases which do match a lease expression. + /// Returns a that only includes leases whose is + /// a particular value. + /// + /// The lease scope + /// + /// A that only includes leases whose is + /// . + /// + TFilter LeaseScopeEq(string scope); + + /// + /// Returns a that only includes leases whose is + /// a particular value. + /// + /// The lease label + /// + /// A that only includes leases whose is + /// . + /// + TFilter LeaseLabelEq(string label); + + /// + /// Returns a that only includes leases whose is + /// a particular value. /// - /// The type of lease in the lease expression. - /// The lease expression. + /// The lease value /// - /// A that only includes leases which do match - /// . + /// A that only includes leases whose is + /// . /// - TFilter LeaseMatches(Expression> leaseExpression); + TFilter LeaseValueEq(string value); } diff --git a/src/EntityDb.Abstractions/Queries/FilterBuilders/ITagFilterBuilder.cs b/src/EntityDb.Abstractions/Queries/FilterBuilders/ITagFilterBuilder.cs index c866ead2..b8454772 100644 --- a/src/EntityDb.Abstractions/Queries/FilterBuilders/ITagFilterBuilder.cs +++ b/src/EntityDb.Abstractions/Queries/FilterBuilders/ITagFilterBuilder.cs @@ -1,5 +1,6 @@ +using EntityDb.Abstractions.Tags; using EntityDb.Abstractions.ValueObjects; -using System; +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; namespace EntityDb.Abstractions.Queries.FilterBuilders; @@ -10,6 +11,12 @@ namespace EntityDb.Abstractions.Queries.FilterBuilders; /// The type of filter used by the repository. public interface ITagFilterBuilder : IFilterBuilder { + /// + [Obsolete("This method will be removed in the future, and may not be supported for all implementations.")] + [ExcludeFromCodeCoverage(Justification = "Obsolete")] + TFilter TagMatches(Expression> tagExpression) + => throw new NotSupportedException(); + /// /// Returns a that only includes tags with an entity id which is contained in a set of /// entity ids. @@ -54,10 +61,24 @@ public interface ITagFilterBuilder : IFilterBuilder TFilter TagTypeIn(params Type[] tagTypes); /// - /// Returns a that only includes tags which do match a tag expression. + /// Returns a that only includes tags whose is + /// a particular value. + /// + /// The tag labels + /// + /// A that only includes tags whose is + /// . + /// + TFilter TagLabelEq(string label); + + /// + /// Returns a that only includes tags whose is + /// a particular value. /// - /// The type of tag in the tag expression. - /// The tag expression. - /// A that only includes tags which do match . - TFilter TagMatches(Expression> tagExpression); + /// The tag values + /// + /// A that only includes tags whose is + /// . + /// + TFilter TagValueEq(string value); } diff --git a/src/EntityDb.Abstractions/Queries/IQuery.cs b/src/EntityDb.Abstractions/Queries/IQuery.cs index e64d2cc4..5b85d6ac 100644 --- a/src/EntityDb.Abstractions/Queries/IQuery.cs +++ b/src/EntityDb.Abstractions/Queries/IQuery.cs @@ -14,4 +14,9 @@ public interface IQuery /// The number of objects to take. /// int? Take { get; } + + /// + /// Driver-specific options for this query + /// + object? Options { get; } } diff --git a/src/EntityDb.Abstractions/Queries/SortBuilders/IAgentSignatureSortBuilder.cs b/src/EntityDb.Abstractions/Queries/SortBuilders/IAgentSignatureSortBuilder.cs index 9e792c54..65d75275 100644 --- a/src/EntityDb.Abstractions/Queries/SortBuilders/IAgentSignatureSortBuilder.cs +++ b/src/EntityDb.Abstractions/Queries/SortBuilders/IAgentSignatureSortBuilder.cs @@ -1,4 +1,4 @@ -using System; +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; namespace EntityDb.Abstractions.Queries.SortBuilders; @@ -9,6 +9,13 @@ namespace EntityDb.Abstractions.Queries.SortBuilders; /// The type of sort used by the repository. public interface IAgentSignatureSortBuilder : ISortBuilder { + /// + [Obsolete("This method will be removed in the future, and may not be supported for all implementations.")] + [ExcludeFromCodeCoverage(Justification = "Obsolete")] + TSort AgentSignatureProperty(bool ascending, + Expression> agentSignatureExpression) + => throw new NotSupportedException(); + /// /// Returns a that orders agentSignatures by entity ids. /// @@ -22,14 +29,4 @@ public interface IAgentSignatureSortBuilder : ISortBuilder /// Pass true for ascending order or false for descending order. /// A that orders agentSignatures by type. TSort AgentSignatureType(bool ascending); - - /// - /// Returns a that orders agentSignatures by a agentSignature expression. - /// - /// The type of agentSignature in the agentSignature expression. - /// Pass true for ascending order or false for descending order. - /// The agentSignature expression. - /// A that orders agentSignatures by . - TSort AgentSignatureProperty(bool ascending, - Expression> agentSignatureExpression); } diff --git a/src/EntityDb.Abstractions/Queries/SortBuilders/ICommandSortBuilder.cs b/src/EntityDb.Abstractions/Queries/SortBuilders/ICommandSortBuilder.cs index 2a5391cf..e4646c09 100644 --- a/src/EntityDb.Abstractions/Queries/SortBuilders/ICommandSortBuilder.cs +++ b/src/EntityDb.Abstractions/Queries/SortBuilders/ICommandSortBuilder.cs @@ -1,4 +1,4 @@ -using System; +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; namespace EntityDb.Abstractions.Queries.SortBuilders; @@ -9,6 +9,12 @@ namespace EntityDb.Abstractions.Queries.SortBuilders; /// The type of sort used by the repository. public interface ICommandSortBuilder : ISortBuilder { + /// + [Obsolete("This method will be removed in the future, and may not be supported for all implementations.")] + [ExcludeFromCodeCoverage(Justification = "Obsolete")] + TSort CommandProperty(bool ascending, Expression> commandExpression) + => throw new NotSupportedException(); + /// /// Returns a that orders commands by entity id. /// @@ -29,13 +35,4 @@ public interface ICommandSortBuilder : ISortBuilder /// Pass true for ascending order or false for descending order. /// A that orders commands by type. TSort CommandType(bool ascending); - - /// - /// Returns a that orders commands by a command expression. - /// - /// The type of command in the command expression. - /// Pass true for ascending order or false for descending order. - /// The command expression. - /// A that orders commands by . - TSort CommandProperty(bool ascending, Expression> commandExpression); } diff --git a/src/EntityDb.Abstractions/Queries/SortBuilders/ILeaseSortBuilder.cs b/src/EntityDb.Abstractions/Queries/SortBuilders/ILeaseSortBuilder.cs index 3aaa2420..310f75cd 100644 --- a/src/EntityDb.Abstractions/Queries/SortBuilders/ILeaseSortBuilder.cs +++ b/src/EntityDb.Abstractions/Queries/SortBuilders/ILeaseSortBuilder.cs @@ -1,4 +1,5 @@ -using System; +using EntityDb.Abstractions.Leases; +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; namespace EntityDb.Abstractions.Queries.SortBuilders; @@ -9,6 +10,12 @@ namespace EntityDb.Abstractions.Queries.SortBuilders; /// The type of sort used by the repository. public interface ILeaseSortBuilder : ISortBuilder { + /// + [Obsolete("This method will be removed in the future, and may not be supported for all implementations.")] + [ExcludeFromCodeCoverage(Justification = "Obsolete")] + TSort LeaseProperty(bool ascending, Expression> leaseExpression) + => throw new NotSupportedException(); + /// /// Returns a that orders leases by entity id. /// @@ -31,11 +38,23 @@ public interface ILeaseSortBuilder : ISortBuilder TSort LeaseType(bool ascending); /// - /// Returns a that orders leases by a lease expression. + /// Returns a that orders leases by . + /// + /// Pass true for ascending order or false for descending order. + /// A that orders leases by . + TSort LeaseScope(bool ascending); + + /// + /// Returns a that orders leases by . + /// + /// Pass true for ascending order or false for descending order. + /// A that orders leases by . + TSort LeaseLabel(bool ascending); + + /// + /// Returns a that orders leases by . /// - /// The type of lease in the lease expression. /// Pass true for ascending order or false for descending order. - /// The lease expression. - /// A that orders leases by . - TSort LeaseProperty(bool ascending, Expression> leaseExpression); + /// A that orders leases by . + TSort LeaseValue(bool ascending); } diff --git a/src/EntityDb.Abstractions/Queries/SortBuilders/ITagSortBuilder.cs b/src/EntityDb.Abstractions/Queries/SortBuilders/ITagSortBuilder.cs index e846e5d4..b1013780 100644 --- a/src/EntityDb.Abstractions/Queries/SortBuilders/ITagSortBuilder.cs +++ b/src/EntityDb.Abstractions/Queries/SortBuilders/ITagSortBuilder.cs @@ -1,4 +1,5 @@ -using System; +using EntityDb.Abstractions.Tags; +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; namespace EntityDb.Abstractions.Queries.SortBuilders; @@ -9,6 +10,12 @@ namespace EntityDb.Abstractions.Queries.SortBuilders; /// The type of sort used by the repository. public interface ITagSortBuilder : ISortBuilder { + /// + [Obsolete("This method will be removed in the future, and may not be supported for all implementations.")] + [ExcludeFromCodeCoverage(Justification = "Obsolete")] + TSort TagProperty(bool ascending, Expression> tagExpression) + => throw new NotSupportedException(); + /// /// Returns a that orders tags by entity id. /// @@ -31,11 +38,16 @@ public interface ITagSortBuilder : ISortBuilder TSort TagType(bool ascending); /// - /// Returns a that orders tags by a tag expression. + /// Returns a that orders tags by . + /// + /// Pass true for ascending order or false for descending order. + /// A that orders tags by . + TSort TagLabel(bool ascending); + + /// + /// Returns a that orders tags by . /// - /// The type of tag in the tag expression. /// Pass true for ascending order or false for descending order. - /// The tag expression. - /// A that orders tags by . - TSort TagProperty(bool ascending, Expression> tagExpression); + /// A that orders tags by . + TSort TagValue(bool ascending); } diff --git a/src/EntityDb.Abstractions/Snapshots/ISnapshotRepository.cs b/src/EntityDb.Abstractions/Snapshots/ISnapshotRepository.cs index 3844189e..6881712a 100644 --- a/src/EntityDb.Abstractions/Snapshots/ISnapshotRepository.cs +++ b/src/EntityDb.Abstractions/Snapshots/ISnapshotRepository.cs @@ -1,9 +1,6 @@ using EntityDb.Abstractions.Disposables; using EntityDb.Abstractions.ValueObjects; -using System; using System.Diagnostics.CodeAnalysis; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.Abstractions.Snapshots; diff --git a/src/EntityDb.Abstractions/Snapshots/ISnapshotRepositoryFactory.cs b/src/EntityDb.Abstractions/Snapshots/ISnapshotRepositoryFactory.cs index 0ea4bfb4..cb5ff674 100644 --- a/src/EntityDb.Abstractions/Snapshots/ISnapshotRepositoryFactory.cs +++ b/src/EntityDb.Abstractions/Snapshots/ISnapshotRepositoryFactory.cs @@ -1,6 +1,4 @@ using EntityDb.Abstractions.Disposables; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.Abstractions.Snapshots; diff --git a/src/EntityDb.Abstractions/Transactions/Builders/ITransactionBuilderFactory.cs b/src/EntityDb.Abstractions/Transactions/Builders/ITransactionBuilderFactory.cs index dd0e3a47..bfedfb7d 100644 --- a/src/EntityDb.Abstractions/Transactions/Builders/ITransactionBuilderFactory.cs +++ b/src/EntityDb.Abstractions/Transactions/Builders/ITransactionBuilderFactory.cs @@ -1,6 +1,4 @@ using EntityDb.Abstractions.ValueObjects; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.Abstractions.Transactions.Builders; diff --git a/src/EntityDb.Abstractions/Transactions/ITransactionRepository.cs b/src/EntityDb.Abstractions/Transactions/ITransactionRepository.cs index fda634f7..c8c78de2 100644 --- a/src/EntityDb.Abstractions/Transactions/ITransactionRepository.cs +++ b/src/EntityDb.Abstractions/Transactions/ITransactionRepository.cs @@ -4,8 +4,7 @@ using EntityDb.Abstractions.Queries; using EntityDb.Abstractions.Tags; using EntityDb.Abstractions.ValueObjects; -using System.Threading; -using System.Threading.Tasks; +using System.Diagnostics.CodeAnalysis; namespace EntityDb.Abstractions.Transactions; @@ -14,13 +13,166 @@ namespace EntityDb.Abstractions.Transactions; /// public interface ITransactionRepository : IDisposableResource { + /// + [ExcludeFromCodeCoverage(Justification = "Obsolete")] + [Obsolete("Please use EnumerateTransactionIds instead! This method will be removed at a future date.")] + Task GetTransactionIds(IAgentSignatureQuery agentSignatureQuery, + CancellationToken cancellationToken = default) + { + return EnumerateTransactionIds(agentSignatureQuery, cancellationToken) + .ToArrayAsync(cancellationToken) + .AsTask(); + } + + /// + [ExcludeFromCodeCoverage(Justification = "Obsolete")] + [Obsolete("Please use EnumerateTransactionIds instead! This method will be removed at a future date.")] + Task GetTransactionIds(ICommandQuery commandQuery, + CancellationToken cancellationToken = default) + { + return EnumerateTransactionIds(commandQuery, cancellationToken) + .ToArrayAsync(cancellationToken) + .AsTask(); + } + + /// + [ExcludeFromCodeCoverage(Justification = "Obsolete")] + [Obsolete("Please use EnumerateTransactionIds instead! This method will be removed at a future date.")] + Task GetTransactionIds(ILeaseQuery leaseQuery, + CancellationToken cancellationToken = default) + { + return EnumerateTransactionIds(leaseQuery, cancellationToken) + .ToArrayAsync(cancellationToken) + .AsTask(); + } + + /// + [ExcludeFromCodeCoverage(Justification = "Obsolete")] + [Obsolete("Please use EnumerateTransactionIds instead! This method will be removed at a future date.")] + Task GetTransactionIds(ITagQuery tagQuery, CancellationToken cancellationToken = default) + { + return EnumerateTransactionIds(tagQuery, cancellationToken) + .ToArrayAsync(cancellationToken) + .AsTask(); + } + + /// + [ExcludeFromCodeCoverage(Justification = "Obsolete")] + [Obsolete("Please use EnumerateEntityIds instead! This method will be removed at a future date.")] + public Task GetEntityIds(IAgentSignatureQuery agentSignatureQuery, + CancellationToken cancellationToken = default) + { + return EnumerateEntityIds(agentSignatureQuery, cancellationToken) + .ToArrayAsync(cancellationToken) + .AsTask(); + } + + /// + [ExcludeFromCodeCoverage(Justification = "Obsolete")] + [Obsolete("Please use EnumerateEntityIds instead! This method will be removed at a future date.")] + public Task GetEntityIds(ICommandQuery commandQuery, + CancellationToken cancellationToken = default) + { + return EnumerateEntityIds(commandQuery, cancellationToken) + .ToArrayAsync(cancellationToken) + .AsTask(); + } + + /// + [ExcludeFromCodeCoverage(Justification = "Obsolete")] + [Obsolete("Please use EnumerateEntityIds instead! This method will be removed at a future date.")] + public Task GetEntityIds(ILeaseQuery leaseQuery, + CancellationToken cancellationToken = default) + { + return EnumerateEntityIds(leaseQuery, cancellationToken) + .ToArrayAsync(cancellationToken) + .AsTask(); + } + + /// + [ExcludeFromCodeCoverage(Justification = "Obsolete")] + [Obsolete("Please use EnumerateEntityIds instead! This method will be removed at a future date.")] + public Task GetEntityIds(ITagQuery tagQuery, + CancellationToken cancellationToken = default) + { + return EnumerateEntityIds(tagQuery, cancellationToken) + .ToArrayAsync(cancellationToken) + .AsTask(); + } + + /// + [ExcludeFromCodeCoverage(Justification = "Obsolete")] + [Obsolete("Please use EnumerateAgentSignatures instead! This method will be removed at a future date.")] + Task GetAgentSignatures(IAgentSignatureQuery agentSignatureQuery, + CancellationToken cancellationToken = default) + { + return EnumerateAgentSignatures(agentSignatureQuery, cancellationToken) + .ToArrayAsync(cancellationToken) + .AsTask(); + } + + /// + [ExcludeFromCodeCoverage(Justification = "Obsolete")] + [Obsolete("Please use EnumerateCommands instead! This method will be removed at a future date.")] + Task GetCommands(ICommandQuery commandQuery, + CancellationToken cancellationToken = default) + { + return EnumerateCommands(commandQuery, cancellationToken) + .ToArrayAsync(cancellationToken) + .AsTask(); + } + + /// + [ExcludeFromCodeCoverage(Justification = "Obsolete")] + [Obsolete("Please use EnumerateLeases instead! This method will be removed at a future date.")] + Task GetLeases(ILeaseQuery leaseQuery, + CancellationToken cancellationToken = default) + { + return EnumerateLeases(leaseQuery, cancellationToken) + .ToArrayAsync(cancellationToken) + .AsTask(); + } + + /// + [ExcludeFromCodeCoverage(Justification = "Obsolete")] + [Obsolete("Please use EnumerateTags instead! This method will be removed at a future date.")] + Task GetTags(ITagQuery tagQuery, + CancellationToken cancellationToken = default) + { + return EnumerateTags(tagQuery, cancellationToken) + .ToArrayAsync(cancellationToken) + .AsTask(); + } + + /// + [ExcludeFromCodeCoverage(Justification = "Obsolete")] + [Obsolete("Please use EnumerateAnnotatedAgentSignatures instead! This method will be removed at a future date.")] + Task[]> GetAnnotatedAgentSignatures(IAgentSignatureQuery agentSignatureQuery, + CancellationToken cancellationToken = default) + { + return EnumerateAnnotatedAgentSignatures(agentSignatureQuery, cancellationToken) + .ToArrayAsync(cancellationToken) + .AsTask(); + } + + /// + [ExcludeFromCodeCoverage(Justification = "Obsolete")] + [Obsolete("Please use EnumerateAnnotatedCommands instead! This method will be removed at a future date.")] + Task[]> GetAnnotatedCommands(ICommandQuery commandQuery, + CancellationToken cancellationToken = default) + { + return EnumerateAnnotatedCommands(commandQuery, cancellationToken) + .ToArrayAsync(cancellationToken) + .AsTask(); + } + /// /// Returns the transaction ids which are found by a agentSignature query. /// /// The agentSignature query. /// A cancellation token. /// The transaction ids which are found by . - Task GetTransactionIds(IAgentSignatureQuery agentSignatureQuery, + IAsyncEnumerable EnumerateTransactionIds(IAgentSignatureQuery agentSignatureQuery, CancellationToken cancellationToken = default); /// @@ -29,7 +181,8 @@ Task GetTransactionIds(IAgentSignatureQuery agentSignatureQuery, /// The command query. /// A cancellation token. /// The transaction ids which are found by . - Task GetTransactionIds(ICommandQuery commandQuery, CancellationToken cancellationToken = default); + IAsyncEnumerable EnumerateTransactionIds(ICommandQuery commandQuery, + CancellationToken cancellationToken = default); /// /// Returns the transaction ids which are found by a lease query. @@ -37,7 +190,8 @@ Task GetTransactionIds(IAgentSignatureQuery agentSignatureQuery, /// The lease query. /// A cancellation token. /// The transaction ids which are found by . - Task GetTransactionIds(ILeaseQuery leaseQuery, CancellationToken cancellationToken = default); + IAsyncEnumerable EnumerateTransactionIds(ILeaseQuery leaseQuery, + CancellationToken cancellationToken = default); /// /// Returns the transaction ids which are found by a tag query. @@ -45,7 +199,8 @@ Task GetTransactionIds(IAgentSignatureQuery agentSignatureQuery, /// The tag query. /// A cancellation token. /// The transaction ids which are found by . - Task GetTransactionIds(ITagQuery tagQuery, CancellationToken cancellationToken = default); + IAsyncEnumerable EnumerateTransactionIds(ITagQuery tagQuery, + CancellationToken cancellationToken = default); /// /// Returns the entity ids which are found by a agentSignature query. @@ -53,7 +208,8 @@ Task GetTransactionIds(IAgentSignatureQuery agentSignatureQuery, /// The agentSignature query. /// A cancellation token. /// The entity ids which are found by . - Task GetEntityIds(IAgentSignatureQuery agentSignatureQuery, CancellationToken cancellationToken = default); + IAsyncEnumerable EnumerateEntityIds(IAgentSignatureQuery agentSignatureQuery, + CancellationToken cancellationToken = default); /// /// Returns the entity ids which are found by a command query. @@ -61,7 +217,8 @@ Task GetTransactionIds(IAgentSignatureQuery agentSignatureQuery, /// The command query. /// A cancellation token. /// The entity ids which are found by . - Task GetEntityIds(ICommandQuery commandQuery, CancellationToken cancellationToken = default); + IAsyncEnumerable EnumerateEntityIds(ICommandQuery commandQuery, + CancellationToken cancellationToken = default); /// /// Returns the entity ids which are found by a lease query. @@ -69,7 +226,8 @@ Task GetTransactionIds(IAgentSignatureQuery agentSignatureQuery, /// The lease query. /// A cancellation token. /// The entity ids which are found by . - Task GetEntityIds(ILeaseQuery leaseQuery, CancellationToken cancellationToken = default); + IAsyncEnumerable EnumerateEntityIds(ILeaseQuery leaseQuery, + CancellationToken cancellationToken = default); /// /// Returns the entity ids which are found by a tag query. @@ -77,7 +235,8 @@ Task GetTransactionIds(IAgentSignatureQuery agentSignatureQuery, /// The tag query. /// A cancellation token. /// The entity ids which are found by . - Task GetEntityIds(ITagQuery tagQuery, CancellationToken cancellationToken = default); + IAsyncEnumerable EnumerateEntityIds(ITagQuery tagQuery, + CancellationToken cancellationToken = default); /// /// Returns the agentSignatures which are found by a agentSignature query. @@ -85,7 +244,7 @@ Task GetTransactionIds(IAgentSignatureQuery agentSignatureQuery, /// The agentSignature query. /// A cancellation token. /// The agentSignatures which are found by . - Task GetAgentSignatures(IAgentSignatureQuery agentSignatureQuery, + IAsyncEnumerable EnumerateAgentSignatures(IAgentSignatureQuery agentSignatureQuery, CancellationToken cancellationToken = default); /// @@ -94,7 +253,8 @@ Task GetAgentSignatures(IAgentSignatureQuery agentSignatureQuery, /// The command query. /// A cancellation token. /// The commands which are found by . - Task GetCommands(ICommandQuery commandQuery, CancellationToken cancellationToken = default); + IAsyncEnumerable EnumerateCommands(ICommandQuery commandQuery, + CancellationToken cancellationToken = default); /// /// Returns the leases which are found by a lease query. @@ -102,7 +262,8 @@ Task GetAgentSignatures(IAgentSignatureQuery agentSignatureQuery, /// The lease query. /// A cancellation token. /// The leases which are found by . - Task GetLeases(ILeaseQuery leaseQuery, CancellationToken cancellationToken = default); + IAsyncEnumerable EnumerateLeases(ILeaseQuery leaseQuery, + CancellationToken cancellationToken = default); /// /// Returns the tags which are found by a tag query. @@ -110,7 +271,8 @@ Task GetAgentSignatures(IAgentSignatureQuery agentSignatureQuery, /// The tag query. /// A cancellation token. /// The tags which are found by . - Task GetTags(ITagQuery tagQuery, CancellationToken cancellationToken = default); + IAsyncEnumerable EnumerateTags(ITagQuery tagQuery, + CancellationToken cancellationToken = default); /// /// Returns the annotated agent signatures which are found by an agent signature query. @@ -118,7 +280,7 @@ Task GetAgentSignatures(IAgentSignatureQuery agentSignatureQuery, /// The agent signature query. /// A cancellation token. /// The annotated agent signatures which are found by . - Task[]> GetAnnotatedAgentSignatures(IAgentSignatureQuery agentSignatureQuery, + IAsyncEnumerable> EnumerateAnnotatedAgentSignatures(IAgentSignatureQuery agentSignatureQuery, CancellationToken cancellationToken = default); /// @@ -127,7 +289,7 @@ Task[]> GetAnnotatedAgentSignatures(IAgentSignatureQ /// The command query. /// A cancellation token. /// The annotated commands which are found by . - Task[]> GetAnnotatedCommands(ICommandQuery commandQuery, + IAsyncEnumerable> EnumerateAnnotatedCommands(ICommandQuery commandQuery, CancellationToken cancellationToken = default); /// diff --git a/src/EntityDb.Abstractions/Transactions/ITransactionRepositoryFactory.cs b/src/EntityDb.Abstractions/Transactions/ITransactionRepositoryFactory.cs index eb1778f2..18dc6d0a 100644 --- a/src/EntityDb.Abstractions/Transactions/ITransactionRepositoryFactory.cs +++ b/src/EntityDb.Abstractions/Transactions/ITransactionRepositoryFactory.cs @@ -1,6 +1,4 @@ using EntityDb.Abstractions.Disposables; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.Abstractions.Transactions; diff --git a/src/EntityDb.Abstractions/ValueObjects/Id.cs b/src/EntityDb.Abstractions/ValueObjects/Id.cs index 9d57c38b..200b26e5 100644 --- a/src/EntityDb.Abstractions/ValueObjects/Id.cs +++ b/src/EntityDb.Abstractions/ValueObjects/Id.cs @@ -1,5 +1,3 @@ -using System; - namespace EntityDb.Abstractions.ValueObjects; /// diff --git a/src/EntityDb.Abstractions/ValueObjects/TimeStamp.cs b/src/EntityDb.Abstractions/ValueObjects/TimeStamp.cs index 00171e5f..12cac34e 100644 --- a/src/EntityDb.Abstractions/ValueObjects/TimeStamp.cs +++ b/src/EntityDb.Abstractions/ValueObjects/TimeStamp.cs @@ -1,5 +1,4 @@ -using System; -using System.Globalization; +using System.Globalization; namespace EntityDb.Abstractions.ValueObjects; @@ -9,6 +8,8 @@ namespace EntityDb.Abstractions.ValueObjects; /// The backing value. public readonly record struct TimeStamp(DateTime Value) { + private const long TicksPerMicrosecond = TimeSpan.TicksPerMillisecond / 1000; + /// /// The value of this constant is equivalent to 00:00:00.0000000 UTC, January 1, 1970. /// @@ -28,6 +29,15 @@ public TimeStamp WithMillisecondPrecision() return new TimeStamp(Value - TimeSpan.FromTicks(Value.Ticks % TimeSpan.TicksPerMillisecond)); } + /// + /// Gets a rounded down to the nearest microsecond. + /// + /// A rounded down to the nearest microsecond. + public TimeStamp WithMicrosecondPrecision() + { + return new TimeStamp(Value - TimeSpan.FromTicks(Value.Ticks % TicksPerMicrosecond)); + } + /// /// Converts the value of the current object to /// its equivalent string representation using the formatting diff --git a/src/EntityDb.Abstractions/packages.lock.json b/src/EntityDb.Abstractions/packages.lock.json index 2fca7fd9..7636783a 100644 --- a/src/EntityDb.Abstractions/packages.lock.json +++ b/src/EntityDb.Abstractions/packages.lock.json @@ -1,6 +1,21 @@ { "version": 1, "dependencies": { - "net6.0": {} + "net6.0": { + "System.Linq.Async": { + "type": "Direct", + "requested": "[6.0.1, )", + "resolved": "6.0.1", + "contentHash": "0YhHcaroWpQ9UCot3Pizah7ryAzQhNvobLMSxeDIGmnXfkQn8u5owvpOH0K6EVB+z9L7u6Cc4W17Br/+jyttEQ==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "6.0.0" + } + }, + "Microsoft.Bcl.AsyncInterfaces": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==" + } + } } } \ No newline at end of file diff --git a/src/EntityDb.Common/Agents/AgentAccessorChain.cs b/src/EntityDb.Common/Agents/AgentAccessorChain.cs index ebcb33de..a6d9f5d2 100644 --- a/src/EntityDb.Common/Agents/AgentAccessorChain.cs +++ b/src/EntityDb.Common/Agents/AgentAccessorChain.cs @@ -3,10 +3,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using System; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.Common.Agents; diff --git a/src/EntityDb.Common/Agents/AgentAccessorChainOptions.cs b/src/EntityDb.Common/Agents/AgentAccessorChainOptions.cs index d6480699..b63bd145 100644 --- a/src/EntityDb.Common/Agents/AgentAccessorChainOptions.cs +++ b/src/EntityDb.Common/Agents/AgentAccessorChainOptions.cs @@ -1,7 +1,5 @@ using EntityDb.Abstractions.Agents; using Microsoft.Extensions.DependencyInjection; -using System; -using System.Collections.Generic; namespace EntityDb.Common.Agents; diff --git a/src/EntityDb.Common/Agents/UnknownAgentAccessor.cs b/src/EntityDb.Common/Agents/UnknownAgentAccessor.cs index 4a9526e7..c06be995 100644 --- a/src/EntityDb.Common/Agents/UnknownAgentAccessor.cs +++ b/src/EntityDb.Common/Agents/UnknownAgentAccessor.cs @@ -1,7 +1,4 @@ using EntityDb.Abstractions.Agents; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.Common.Agents; diff --git a/src/EntityDb.Common/Agents/UnknownAgentSignature.cs b/src/EntityDb.Common/Agents/UnknownAgentSignature.cs index 9a9f8b20..b10b02a4 100644 --- a/src/EntityDb.Common/Agents/UnknownAgentSignature.cs +++ b/src/EntityDb.Common/Agents/UnknownAgentSignature.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; - -namespace EntityDb.Common.Agents; +namespace EntityDb.Common.Agents; /// /// Represents the signature of an unknown actor. diff --git a/src/EntityDb.Common/Annotations/EntitiesAnnotation.cs b/src/EntityDb.Common/Annotations/EntitiesAnnotation.cs index d172f014..e765b92a 100644 --- a/src/EntityDb.Common/Annotations/EntitiesAnnotation.cs +++ b/src/EntityDb.Common/Annotations/EntitiesAnnotation.cs @@ -1,6 +1,5 @@ using EntityDb.Abstractions.Annotations; using EntityDb.Abstractions.ValueObjects; -using System; namespace EntityDb.Common.Annotations; diff --git a/src/EntityDb.Common/Annotations/EntityAnnotation.cs b/src/EntityDb.Common/Annotations/EntityAnnotation.cs index 753cabad..597f0d8f 100644 --- a/src/EntityDb.Common/Annotations/EntityAnnotation.cs +++ b/src/EntityDb.Common/Annotations/EntityAnnotation.cs @@ -1,6 +1,5 @@ using EntityDb.Abstractions.Annotations; using EntityDb.Abstractions.ValueObjects; -using System; namespace EntityDb.Common.Annotations; diff --git a/src/EntityDb.Common/Commands/IAddLeasesCommand.cs b/src/EntityDb.Common/Commands/IAddLeasesCommand.cs index 99c7a2a3..3064a044 100644 --- a/src/EntityDb.Common/Commands/IAddLeasesCommand.cs +++ b/src/EntityDb.Common/Commands/IAddLeasesCommand.cs @@ -1,7 +1,6 @@ using EntityDb.Abstractions.Leases; using EntityDb.Abstractions.ValueObjects; using EntityDb.Common.Transactions.Builders; -using System.Collections.Generic; namespace EntityDb.Common.Commands; diff --git a/src/EntityDb.Common/Commands/IAddTagsCommand.cs b/src/EntityDb.Common/Commands/IAddTagsCommand.cs index 4f0809c9..305a4b35 100644 --- a/src/EntityDb.Common/Commands/IAddTagsCommand.cs +++ b/src/EntityDb.Common/Commands/IAddTagsCommand.cs @@ -1,7 +1,6 @@ using EntityDb.Abstractions.Tags; using EntityDb.Abstractions.ValueObjects; using EntityDb.Common.Transactions.Builders; -using System.Collections.Generic; namespace EntityDb.Common.Commands; diff --git a/src/EntityDb.Common/Commands/IDeleteLeasesCommand.cs b/src/EntityDb.Common/Commands/IDeleteLeasesCommand.cs index 76293c7b..a8931b2d 100644 --- a/src/EntityDb.Common/Commands/IDeleteLeasesCommand.cs +++ b/src/EntityDb.Common/Commands/IDeleteLeasesCommand.cs @@ -1,7 +1,6 @@ using EntityDb.Abstractions.Leases; using EntityDb.Abstractions.ValueObjects; using EntityDb.Common.Transactions.Builders; -using System.Collections.Generic; namespace EntityDb.Common.Commands; diff --git a/src/EntityDb.Common/Commands/IDeleteTagsCommand.cs b/src/EntityDb.Common/Commands/IDeleteTagsCommand.cs index d408a1e6..3fb14693 100644 --- a/src/EntityDb.Common/Commands/IDeleteTagsCommand.cs +++ b/src/EntityDb.Common/Commands/IDeleteTagsCommand.cs @@ -1,7 +1,6 @@ using EntityDb.Abstractions.Tags; using EntityDb.Abstractions.ValueObjects; using EntityDb.Common.Transactions.Builders; -using System.Collections.Generic; namespace EntityDb.Common.Commands; diff --git a/src/EntityDb.Common/Disposables/DisposableResourceBaseClass.cs b/src/EntityDb.Common/Disposables/DisposableResourceBaseClass.cs index d0ae36f2..084045af 100644 --- a/src/EntityDb.Common/Disposables/DisposableResourceBaseClass.cs +++ b/src/EntityDb.Common/Disposables/DisposableResourceBaseClass.cs @@ -1,6 +1,5 @@ using EntityDb.Abstractions.Disposables; using System.Diagnostics.CodeAnalysis; -using System.Threading.Tasks; namespace EntityDb.Common.Disposables; diff --git a/src/EntityDb.Common/Disposables/DisposableResourceBaseRecord.cs b/src/EntityDb.Common/Disposables/DisposableResourceBaseRecord.cs index 340d7669..caf4597c 100644 --- a/src/EntityDb.Common/Disposables/DisposableResourceBaseRecord.cs +++ b/src/EntityDb.Common/Disposables/DisposableResourceBaseRecord.cs @@ -1,6 +1,5 @@ using EntityDb.Abstractions.Disposables; using System.Diagnostics.CodeAnalysis; -using System.Threading.Tasks; namespace EntityDb.Common.Disposables; diff --git a/src/EntityDb.Common/Documents/IEntitiesDocument.cs b/src/EntityDb.Common/Documents/IEntitiesDocument.cs new file mode 100644 index 00000000..3ba5cfe5 --- /dev/null +++ b/src/EntityDb.Common/Documents/IEntitiesDocument.cs @@ -0,0 +1,8 @@ +using EntityDb.Abstractions.ValueObjects; + +namespace EntityDb.Common.Documents; + +internal interface IEntitiesDocument : ITransactionDocument +{ + Id[] EntityIds { get; } +} diff --git a/src/EntityDb.Common/Documents/IEntityDocument.cs b/src/EntityDb.Common/Documents/IEntityDocument.cs new file mode 100644 index 00000000..d6ae722c --- /dev/null +++ b/src/EntityDb.Common/Documents/IEntityDocument.cs @@ -0,0 +1,9 @@ +using EntityDb.Abstractions.ValueObjects; + +namespace EntityDb.Common.Documents; + +internal interface IEntityDocument : ITransactionDocument +{ + Id EntityId { get; } + VersionNumber EntityVersionNumber { get; } +} diff --git a/src/EntityDb.Common/Documents/ITransactionDocument.cs b/src/EntityDb.Common/Documents/ITransactionDocument.cs new file mode 100644 index 00000000..8008b49b --- /dev/null +++ b/src/EntityDb.Common/Documents/ITransactionDocument.cs @@ -0,0 +1,14 @@ +using EntityDb.Abstractions.ValueObjects; + +namespace EntityDb.Common.Documents; + +internal interface ITransactionDocument +{ + Id TransactionId { get; } + + TimeStamp TransactionTimeStamp { get; } + + string DataType { get; } + + TSerializedData Data { get; } +} diff --git a/src/EntityDb.Common/Entities/EntityRepository.cs b/src/EntityDb.Common/Entities/EntityRepository.cs index 4c5fd6c6..a7db31fd 100644 --- a/src/EntityDb.Common/Entities/EntityRepository.cs +++ b/src/EntityDb.Common/Entities/EntityRepository.cs @@ -6,10 +6,6 @@ using EntityDb.Common.Exceptions; using EntityDb.Common.Queries; using Microsoft.Extensions.DependencyInjection; -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.Common.Entities; @@ -42,9 +38,14 @@ public async Task GetSnapshot(Pointer entityPointer, CancellationToken var commandQuery = new GetEntityCommandsQuery(entityPointer, snapshot.GetVersionNumber()); - var commands = await TransactionRepository.GetCommands(commandQuery, cancellationToken); + var commands = TransactionRepository.EnumerateCommands(commandQuery, cancellationToken); - var entity = snapshot.Reduce(commands); + var entity = snapshot; + + await foreach (var command in commands) + { + entity = entity.Reduce(command); + } if (!entityPointer.IsSatisfiedBy(entity.GetVersionNumber())) { diff --git a/src/EntityDb.Common/Entities/EntityRepositoryFactory.cs b/src/EntityDb.Common/Entities/EntityRepositoryFactory.cs index 38956c75..0519305c 100644 --- a/src/EntityDb.Common/Entities/EntityRepositoryFactory.cs +++ b/src/EntityDb.Common/Entities/EntityRepositoryFactory.cs @@ -1,9 +1,6 @@ using EntityDb.Abstractions.Entities; using EntityDb.Abstractions.Snapshots; using EntityDb.Abstractions.Transactions; -using System; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.Common.Entities; diff --git a/src/EntityDb.Common/Entities/IEntity.cs b/src/EntityDb.Common/Entities/IEntity.cs index baa9c618..a0b3ac9a 100644 --- a/src/EntityDb.Common/Entities/IEntity.cs +++ b/src/EntityDb.Common/Entities/IEntity.cs @@ -8,10 +8,17 @@ namespace EntityDb.Common.Entities; /// The type of the entity. public interface IEntity : ISnapshot { + /// + [Obsolete("Please use Reduce(object) instead. This method is no longer in supported.", true)] + TEntity Reduce(params object[] command) + { + throw new NotSupportedException(); + } + /// /// Returns a new that incorporates the commands. /// - /// The commands - /// A new that incorporates . - TEntity Reduce(params object[] commands); + /// The command + /// A new that incorporates . + TEntity Reduce(object command); } diff --git a/src/EntityDb.Common/Envelopes/EnvelopeHeaders.cs b/src/EntityDb.Common/Envelopes/EnvelopeHeaders.cs index e007f50d..6c076033 100644 --- a/src/EntityDb.Common/Envelopes/EnvelopeHeaders.cs +++ b/src/EntityDb.Common/Envelopes/EnvelopeHeaders.cs @@ -1,6 +1,4 @@ using EntityDb.Common.TypeResolvers; -using System; -using System.Collections.Generic; namespace EntityDb.Common.Envelopes; diff --git a/src/EntityDb.Common/Envelopes/EnvelopeHelper.cs b/src/EntityDb.Common/Envelopes/EnvelopeHelper.cs index e5310467..81c45e15 100644 --- a/src/EntityDb.Common/Envelopes/EnvelopeHelper.cs +++ b/src/EntityDb.Common/Envelopes/EnvelopeHelper.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; +using System.Diagnostics.CodeAnalysis; namespace EntityDb.Common.Envelopes; diff --git a/src/EntityDb.Common/Envelopes/IEnvelopeService.cs b/src/EntityDb.Common/Envelopes/IEnvelopeService.cs index e4e35366..4f3a3e31 100644 --- a/src/EntityDb.Common/Envelopes/IEnvelopeService.cs +++ b/src/EntityDb.Common/Envelopes/IEnvelopeService.cs @@ -1,12 +1,8 @@ namespace EntityDb.Common.Envelopes; -internal interface IEnvelopeService +internal interface IEnvelopeService { - Envelope Deconstruct(TData data); + TSerializedData Serialize(TData data); - byte[] Serialize(Envelope envelope); - - Envelope Deserialize(byte[] rawData); - - TData Reconstruct(Envelope envelope); + TData Deserialize(TSerializedData serializedData); } diff --git a/src/EntityDb.Common/Exceptions/CannotResolveTypeException.cs b/src/EntityDb.Common/Exceptions/CannotResolveTypeException.cs index 5fe6cd47..477ca4b4 100644 --- a/src/EntityDb.Common/Exceptions/CannotResolveTypeException.cs +++ b/src/EntityDb.Common/Exceptions/CannotResolveTypeException.cs @@ -1,5 +1,4 @@ using EntityDb.Common.TypeResolvers; -using System; namespace EntityDb.Common.Exceptions; diff --git a/src/EntityDb.Common/Exceptions/CannotWriteInReadOnlyModeException.cs b/src/EntityDb.Common/Exceptions/CannotWriteInReadOnlyModeException.cs index ce3fa12b..fddbef98 100644 --- a/src/EntityDb.Common/Exceptions/CannotWriteInReadOnlyModeException.cs +++ b/src/EntityDb.Common/Exceptions/CannotWriteInReadOnlyModeException.cs @@ -1,5 +1,4 @@ using EntityDb.Abstractions.Transactions; -using System; namespace EntityDb.Common.Exceptions; diff --git a/src/EntityDb.Common/Exceptions/DeserializeException.cs b/src/EntityDb.Common/Exceptions/DeserializeException.cs index 97d2ec27..ce345af7 100644 --- a/src/EntityDb.Common/Exceptions/DeserializeException.cs +++ b/src/EntityDb.Common/Exceptions/DeserializeException.cs @@ -1,6 +1,4 @@ -using System; - -namespace EntityDb.Common.Exceptions; +namespace EntityDb.Common.Exceptions; /// /// The exception that is thrown when an object envelope cannot be deserialized. Possible objects include: diff --git a/src/EntityDb.Common/Exceptions/EntityAlreadyKnownException.cs b/src/EntityDb.Common/Exceptions/EntityAlreadyKnownException.cs index cb5ded65..0aa2967a 100644 --- a/src/EntityDb.Common/Exceptions/EntityAlreadyKnownException.cs +++ b/src/EntityDb.Common/Exceptions/EntityAlreadyKnownException.cs @@ -1,6 +1,5 @@ using EntityDb.Abstractions.ValueObjects; using EntityDb.Common.Transactions.Builders; -using System; namespace EntityDb.Common.Exceptions; diff --git a/src/EntityDb.Common/Exceptions/NoAgentException.cs b/src/EntityDb.Common/Exceptions/NoAgentException.cs index e5f251d1..519773fb 100644 --- a/src/EntityDb.Common/Exceptions/NoAgentException.cs +++ b/src/EntityDb.Common/Exceptions/NoAgentException.cs @@ -1,5 +1,4 @@ using EntityDb.Abstractions.Agents; -using System; namespace EntityDb.Common.Exceptions; diff --git a/src/EntityDb.Common/Exceptions/OptimisticConcurrencyException.cs b/src/EntityDb.Common/Exceptions/OptimisticConcurrencyException.cs index 9e4fc7dd..3f89bd68 100644 --- a/src/EntityDb.Common/Exceptions/OptimisticConcurrencyException.cs +++ b/src/EntityDb.Common/Exceptions/OptimisticConcurrencyException.cs @@ -2,8 +2,6 @@ using EntityDb.Abstractions.Transactions.Steps; using EntityDb.Abstractions.ValueObjects; using Microsoft.Extensions.Logging; -using System; -using System.Threading; namespace EntityDb.Common.Exceptions; diff --git a/src/EntityDb.Common/Exceptions/SerializeException.cs b/src/EntityDb.Common/Exceptions/SerializeException.cs index 7f080cd7..5b807cdb 100644 --- a/src/EntityDb.Common/Exceptions/SerializeException.cs +++ b/src/EntityDb.Common/Exceptions/SerializeException.cs @@ -1,6 +1,4 @@ -using System; - -namespace EntityDb.Common.Exceptions; +namespace EntityDb.Common.Exceptions; /// /// The exception that is thrown when an object envelope cannot be serialized. Possible objects include: diff --git a/src/EntityDb.Common/Exceptions/SnapshotPointerDoesNotExistException.cs b/src/EntityDb.Common/Exceptions/SnapshotPointerDoesNotExistException.cs index 9ce07b72..134defd2 100644 --- a/src/EntityDb.Common/Exceptions/SnapshotPointerDoesNotExistException.cs +++ b/src/EntityDb.Common/Exceptions/SnapshotPointerDoesNotExistException.cs @@ -1,6 +1,4 @@ -using System; - -namespace EntityDb.Common.Exceptions; +namespace EntityDb.Common.Exceptions; /// /// The exception that is thrown when an actor requests a snapshot that does not exist. diff --git a/src/EntityDb.Common/Exceptions/VersionZeroReservedException.cs b/src/EntityDb.Common/Exceptions/VersionZeroReservedException.cs index cb28e73f..fffc3a52 100644 --- a/src/EntityDb.Common/Exceptions/VersionZeroReservedException.cs +++ b/src/EntityDb.Common/Exceptions/VersionZeroReservedException.cs @@ -1,8 +1,6 @@ using EntityDb.Abstractions.Transactions; using EntityDb.Abstractions.Transactions.Steps; using EntityDb.Abstractions.ValueObjects; -using System; -using System.Threading; namespace EntityDb.Common.Exceptions; diff --git a/src/EntityDb.Common/Extensions/DocumentsExtensions.cs b/src/EntityDb.Common/Extensions/DocumentsExtensions.cs new file mode 100644 index 00000000..9e71994e --- /dev/null +++ b/src/EntityDb.Common/Extensions/DocumentsExtensions.cs @@ -0,0 +1,87 @@ +using EntityDb.Abstractions.Annotations; +using EntityDb.Abstractions.ValueObjects; +using EntityDb.Common.Annotations; +using EntityDb.Common.Documents; +using EntityDb.Common.Envelopes; +using System.Runtime.CompilerServices; + +namespace EntityDb.Common.Extensions; + +internal static class DocumentsExtensions +{ + public static IAsyncEnumerable EnumerateIds + ( + this IAsyncEnumerable documents, + int? skip, + int? limit, + Func, IAsyncEnumerable> mapToIds + ) + { + var ids = mapToIds + .Invoke(documents) + .Distinct(); + + if (skip.HasValue) + { + ids = ids.Skip(skip.Value); + } + + if (limit.HasValue) + { + ids = ids.Take(limit.Value); + } + + return ids; + } + + public static async IAsyncEnumerable> EnumerateEntityAnnotation + ( + this IAsyncEnumerable documents, + IEnvelopeService envelopeService, + [EnumeratorCancellation] CancellationToken cancellationToken + ) + where TDocument : IEntityDocument + where TData : notnull + { + await using var enumerator = documents.GetAsyncEnumerator(cancellationToken); + + while (await enumerator.MoveNextAsync(cancellationToken)) + { + var document = enumerator.Current; + + yield return EntityAnnotation.CreateFromBoxedData + ( + document.TransactionId, + document.TransactionTimeStamp, + document.EntityId, + document.EntityVersionNumber, + envelopeService.Deserialize(document.Data) + ); + } + } + + public static async IAsyncEnumerable> EnumerateEntitiesAnnotation + ( + this IAsyncEnumerable documents, + IEnvelopeService envelopeService, + [EnumeratorCancellation] CancellationToken cancellationToken + ) + where TDocument : IEntitiesDocument + where TData : notnull + { + await using var enumerator = documents.GetAsyncEnumerator(cancellationToken); + + while (await enumerator.MoveNextAsync(cancellationToken)) + { + var document = enumerator.Current; + + yield return EntitiesAnnotation.CreateFromBoxedData + ( + document.TransactionId, + document.TransactionTimeStamp, + document.EntityIds, + envelopeService.Deserialize(document.Data) + ); + } + } +} diff --git a/src/EntityDb.Common/Extensions/EnvelopeServiceExtensions.cs b/src/EntityDb.Common/Extensions/EnvelopeServiceExtensions.cs deleted file mode 100644 index 7a7198e5..00000000 --- a/src/EntityDb.Common/Extensions/EnvelopeServiceExtensions.cs +++ /dev/null @@ -1,22 +0,0 @@ -using EntityDb.Common.Envelopes; - -namespace EntityDb.Common.Extensions; - -internal static class EnvelopeServiceExtensions -{ - public static byte[] DeconstructAndSerialize(this IEnvelopeService envelopeService, - TData data) - { - var envelope = envelopeService.Deconstruct(data); - - return envelopeService.Serialize(envelope); - } - - public static TData DeserializeAndReconstruct(this IEnvelopeService envelopeService, - byte[] rawData) - { - var envelope = envelopeService.Deserialize(rawData); - - return envelopeService.Reconstruct(envelope); - } -} diff --git a/src/EntityDb.Common/Extensions/ServiceCollectionExtensions.cs b/src/EntityDb.Common/Extensions/ServiceCollectionExtensions.cs index 782d5b39..dcb7b740 100644 --- a/src/EntityDb.Common/Extensions/ServiceCollectionExtensions.cs +++ b/src/EntityDb.Common/Extensions/ServiceCollectionExtensions.cs @@ -11,7 +11,6 @@ using EntityDb.Common.Transactions.Subscribers.Processors; using EntityDb.Common.TypeResolvers; using Microsoft.Extensions.DependencyInjection; -using System; using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Threading.Tasks.Dataflow; @@ -50,6 +49,13 @@ internal static void Add(this IServiceCollection serviceCollection, Se serviceCollection.Add(new ServiceDescriptor(typeof(TService), serviceFactory, serviceLifetime)); } + internal static void Add(this IServiceCollection serviceCollection, ServiceLifetime serviceLifetime) + where TService : class + where TImplementation : TService + { + serviceCollection.Add(new ServiceDescriptor(typeof(TService), typeof(TImplementation), serviceLifetime)); + } + internal static void Add(this IServiceCollection serviceCollection, ServiceLifetime serviceLifetime) where TService : class { diff --git a/src/EntityDb.Common/Polyfills/AsyncEnumerablePolyfill.cs b/src/EntityDb.Common/Polyfills/AsyncEnumerablePolyfill.cs new file mode 100644 index 00000000..86667912 --- /dev/null +++ b/src/EntityDb.Common/Polyfills/AsyncEnumerablePolyfill.cs @@ -0,0 +1,33 @@ +namespace EntityDb.Common.Polyfills; + +internal static class AsyncEnumerablePolyfill +{ + public static IAsyncEnumerable FromResult(IEnumerable enumerable) + { + var enumerator = enumerable.GetEnumerator(); + var current = default(T); + + var asyncEnumerator = AsyncEnumerator.Create + ( + () => + { + var moveNext = enumerator.MoveNext(); + + current = moveNext + ? enumerator.Current + : default; + + return ValueTask.FromResult(moveNext); + }, + () => current!, + () => + { + enumerator.Dispose(); + + return ValueTask.CompletedTask; + } + ); + + return AsyncEnumerable.Create(_ => asyncEnumerator); + } +} diff --git a/src/EntityDb.Common/Projections/IProjection.cs b/src/EntityDb.Common/Projections/IProjection.cs index 7cfc98b6..3706a13d 100644 --- a/src/EntityDb.Common/Projections/IProjection.cs +++ b/src/EntityDb.Common/Projections/IProjection.cs @@ -12,11 +12,11 @@ namespace EntityDb.Common.Projections; public interface IProjection : ISnapshot { /// - /// Returns a new that incorporates the commands for a particular entity id. + /// Returns a new that incorporates the command for a particular entity id. /// - /// The annotated commands. - /// A new that incorporates . - TProjection Reduce(params IEntityAnnotation[] annotatedCommands); + /// The annotated command. + /// A new that incorporates . + TProjection Reduce(IEntityAnnotation annotatedCommand); /// /// Returns a that is used to load the rest of the state for the given projection pointer. diff --git a/src/EntityDb.Common/Projections/ProjectionRepository.cs b/src/EntityDb.Common/Projections/ProjectionRepository.cs index 271bf315..a36af76d 100644 --- a/src/EntityDb.Common/Projections/ProjectionRepository.cs +++ b/src/EntityDb.Common/Projections/ProjectionRepository.cs @@ -5,9 +5,6 @@ using EntityDb.Common.Disposables; using EntityDb.Common.Exceptions; using Microsoft.Extensions.DependencyInjection; -using System; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.Common.Projections; @@ -43,9 +40,12 @@ public async Task GetSnapshot(Pointer projectionPointer, Cancellati var commandQuery = projection.GetCommandQuery(projectionPointer); - var annotatedCommands = await TransactionRepository.GetAnnotatedCommands(commandQuery, cancellationToken); + var annotatedCommands = TransactionRepository.EnumerateAnnotatedCommands(commandQuery, cancellationToken); - projection = projection.Reduce(annotatedCommands); + await foreach (var annotatedCommand in annotatedCommands) + { + projection = projection.Reduce(annotatedCommand); + } if (!projectionPointer.IsSatisfiedBy(projection.GetVersionNumber())) { diff --git a/src/EntityDb.Common/Projections/ProjectionRepositoryFactory.cs b/src/EntityDb.Common/Projections/ProjectionRepositoryFactory.cs index 66ce8c8e..2db48c92 100644 --- a/src/EntityDb.Common/Projections/ProjectionRepositoryFactory.cs +++ b/src/EntityDb.Common/Projections/ProjectionRepositoryFactory.cs @@ -1,9 +1,6 @@ using EntityDb.Abstractions.Projections; using EntityDb.Abstractions.Snapshots; using EntityDb.Abstractions.Transactions; -using System; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.Common.Projections; diff --git a/src/EntityDb.Common/Properties/AssemblyInfo.cs b/src/EntityDb.Common/Properties/AssemblyInfo.cs index 79b6e821..7c37e040 100644 --- a/src/EntityDb.Common/Properties/AssemblyInfo.cs +++ b/src/EntityDb.Common/Properties/AssemblyInfo.cs @@ -1,12 +1,16 @@ using System.Runtime.CompilerServices; // src +[assembly: InternalsVisibleTo("EntityDb.SqlDb")] +[assembly: InternalsVisibleTo("EntityDb.Npgsql")] +[assembly: InternalsVisibleTo("EntityDb.Npgsql.Provisioner")] [assembly: InternalsVisibleTo("EntityDb.InMemory")] [assembly: InternalsVisibleTo("EntityDb.MongoDb")] [assembly: InternalsVisibleTo("EntityDb.MongoDb.Provisioner")] [assembly: InternalsVisibleTo("EntityDb.Mvc")] [assembly: InternalsVisibleTo("EntityDb.Redis")] [assembly: InternalsVisibleTo("EntityDb.Void")] +[assembly: InternalsVisibleTo("EntityDb.Json")] // test [assembly: InternalsVisibleTo("EntityDb.Common.Tests")] diff --git a/src/EntityDb.Common/Queries/DeleteLeasesQuery.cs b/src/EntityDb.Common/Queries/DeleteLeasesQuery.cs index 10c88ef8..bec312f5 100644 --- a/src/EntityDb.Common/Queries/DeleteLeasesQuery.cs +++ b/src/EntityDb.Common/Queries/DeleteLeasesQuery.cs @@ -3,13 +3,10 @@ using EntityDb.Abstractions.Queries.FilterBuilders; using EntityDb.Abstractions.Queries.SortBuilders; using EntityDb.Abstractions.ValueObjects; -using EntityDb.Common.Leases; -using System.Collections.Generic; -using System.Linq; namespace EntityDb.Common.Queries; -internal sealed record DeleteLeasesQuery(Id EntityId, IReadOnlyCollection Leases) : ILeaseQuery +internal sealed record DeleteLeasesQuery(Id EntityId, IReadOnlyCollection Leases, object? Options = null) : ILeaseQuery { public TFilter GetFilter(ILeaseFilterBuilder builder) { @@ -19,10 +16,11 @@ public TFilter GetFilter(ILeaseFilterBuilder builder) builder.Or ( Leases - .Select(deleteLease => builder.LeaseMatches((Lease lease) => - lease.Scope == deleteLease.Scope && - lease.Label == deleteLease.Label && - lease.Value == deleteLease.Value)) + .Select(deleteLease => builder.And( + builder.LeaseScopeEq(deleteLease.Scope), + builder.LeaseLabelEq(deleteLease.Label), + builder.LeaseValueEq(deleteLease.Value) + )) .ToArray() ) ); diff --git a/src/EntityDb.Common/Queries/DeleteTagsQuery.cs b/src/EntityDb.Common/Queries/DeleteTagsQuery.cs index fbb05b00..36d80348 100644 --- a/src/EntityDb.Common/Queries/DeleteTagsQuery.cs +++ b/src/EntityDb.Common/Queries/DeleteTagsQuery.cs @@ -3,13 +3,10 @@ using EntityDb.Abstractions.Queries.SortBuilders; using EntityDb.Abstractions.Tags; using EntityDb.Abstractions.ValueObjects; -using EntityDb.Common.Tags; -using System.Collections.Generic; -using System.Linq; namespace EntityDb.Common.Queries; -internal sealed record DeleteTagsQuery(Id EntityId, IReadOnlyCollection Tags) : ITagQuery +internal sealed record DeleteTagsQuery(Id EntityId, IReadOnlyCollection Tags, object? Options = null) : ITagQuery { public TFilter GetFilter(ITagFilterBuilder builder) { @@ -19,9 +16,10 @@ public TFilter GetFilter(ITagFilterBuilder builder) builder.Or ( Tags - .Select(deleteLease => builder.TagMatches((Tag lease) => - lease.Label == deleteLease.Label && - lease.Value == deleteLease.Value)) + .Select(deleteTag => builder.And( + builder.TagLabelEq(deleteTag.Label), + builder.TagValueEq(deleteTag.Value) + )) .ToArray() ) ); diff --git a/src/EntityDb.Common/Queries/GetEntityQuery.cs b/src/EntityDb.Common/Queries/GetEntityQuery.cs index 06147670..023cec32 100644 --- a/src/EntityDb.Common/Queries/GetEntityQuery.cs +++ b/src/EntityDb.Common/Queries/GetEntityQuery.cs @@ -2,12 +2,11 @@ using EntityDb.Abstractions.Queries.FilterBuilders; using EntityDb.Abstractions.Queries.SortBuilders; using EntityDb.Abstractions.ValueObjects; -using System.Collections.Generic; namespace EntityDb.Common.Queries; internal sealed record GetEntityCommandsQuery - (Pointer EntityPointer, VersionNumber SnapshotVersionNumber) : ICommandQuery + (Pointer EntityPointer, VersionNumber SnapshotVersionNumber, object? Options = null) : ICommandQuery { public TFilter GetFilter(ICommandFilterBuilder builder) { diff --git a/src/EntityDb.Common/Queries/GetLastEntityVersionQuery.cs b/src/EntityDb.Common/Queries/GetLastEntityVersionQuery.cs index 779acf6f..2eda63d3 100644 --- a/src/EntityDb.Common/Queries/GetLastEntityVersionQuery.cs +++ b/src/EntityDb.Common/Queries/GetLastEntityVersionQuery.cs @@ -5,7 +5,7 @@ namespace EntityDb.Common.Queries; -internal sealed record GetLastEntityCommandQuery(Id EntityId) : ICommandQuery +internal sealed record GetLastEntityCommandQuery(Id EntityId, object? Options = null) : ICommandQuery { public TFilter GetFilter(ICommandFilterBuilder builder) { diff --git a/src/EntityDb.Common/Queries/Modified/ModifiedQueryBase.cs b/src/EntityDb.Common/Queries/Modified/ModifiedQueryBase.cs index e16233c1..21e7c06f 100644 --- a/src/EntityDb.Common/Queries/Modified/ModifiedQueryBase.cs +++ b/src/EntityDb.Common/Queries/Modified/ModifiedQueryBase.cs @@ -7,4 +7,6 @@ internal abstract record ModifiedQueryBase(IQuery Query, ModifiedQueryOptions Mo public int? Skip => ModifiedQueryOptions.ReplaceSkip ?? Query.Skip; public int? Take => ModifiedQueryOptions.ReplaceTake ?? Query.Take; + + public object? Options => Query.Options; } diff --git a/src/EntityDb.Common/Queries/SortBuilders/AgentSignatureReverseSortBuilder.cs b/src/EntityDb.Common/Queries/SortBuilders/AgentSignatureReverseSortBuilder.cs index c28334d6..c406503a 100644 --- a/src/EntityDb.Common/Queries/SortBuilders/AgentSignatureReverseSortBuilder.cs +++ b/src/EntityDb.Common/Queries/SortBuilders/AgentSignatureReverseSortBuilder.cs @@ -1,5 +1,5 @@ using EntityDb.Abstractions.Queries.SortBuilders; -using System; +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; namespace EntityDb.Common.Queries.SortBuilders; @@ -19,6 +19,8 @@ public TSort AgentSignatureType(bool ascending) return AgentSignatureSortBuilder.AgentSignatureType(!ascending); } + [Obsolete("This method will be removed in the future, and may not be supported for all implementations.")] + [ExcludeFromCodeCoverage(Justification = "Obsolete")] public TSort AgentSignatureProperty(bool ascending, Expression> agentSignatureExpression) { diff --git a/src/EntityDb.Common/Queries/SortBuilders/CommandReverseSortBuilder.cs b/src/EntityDb.Common/Queries/SortBuilders/CommandReverseSortBuilder.cs index 755223b6..361eab9b 100644 --- a/src/EntityDb.Common/Queries/SortBuilders/CommandReverseSortBuilder.cs +++ b/src/EntityDb.Common/Queries/SortBuilders/CommandReverseSortBuilder.cs @@ -1,5 +1,5 @@ using EntityDb.Abstractions.Queries.SortBuilders; -using System; +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; namespace EntityDb.Common.Queries.SortBuilders; @@ -23,6 +23,8 @@ public TSort CommandType(bool ascending) return CommandSortBuilder.CommandType(!ascending); } + [Obsolete("This method will be removed in the future, and may not be supported for all implementations.")] + [ExcludeFromCodeCoverage(Justification = "Obsolete")] public TSort CommandProperty(bool ascending, Expression> commandExpression) { return CommandSortBuilder.CommandProperty(!ascending, commandExpression); diff --git a/src/EntityDb.Common/Queries/SortBuilders/LeaseReverseSortBuilder.cs b/src/EntityDb.Common/Queries/SortBuilders/LeaseReverseSortBuilder.cs index d43db0a2..e8161b5d 100644 --- a/src/EntityDb.Common/Queries/SortBuilders/LeaseReverseSortBuilder.cs +++ b/src/EntityDb.Common/Queries/SortBuilders/LeaseReverseSortBuilder.cs @@ -1,5 +1,5 @@ using EntityDb.Abstractions.Queries.SortBuilders; -using System; +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; namespace EntityDb.Common.Queries.SortBuilders; @@ -23,8 +23,25 @@ public TSort LeaseType(bool ascending) return LeaseSortBuilder.LeaseType(!ascending); } + [Obsolete("This method will be removed in the future, and may not be supported for all implementations.")] + [ExcludeFromCodeCoverage(Justification = "Obsolete")] public TSort LeaseProperty(bool ascending, Expression> leaseExpression) { return LeaseSortBuilder.LeaseProperty(!ascending, leaseExpression); } + + public TSort LeaseScope(bool ascending) + { + return LeaseSortBuilder.LeaseScope(!ascending); + } + + public TSort LeaseLabel(bool ascending) + { + return LeaseSortBuilder.LeaseLabel(!ascending); + } + + public TSort LeaseValue(bool ascending) + { + return LeaseSortBuilder.LeaseValue(!ascending); + } } diff --git a/src/EntityDb.Common/Queries/SortBuilders/TagReverseSortBuilder.cs b/src/EntityDb.Common/Queries/SortBuilders/TagReverseSortBuilder.cs index 2c04f5cc..fa3364bc 100644 --- a/src/EntityDb.Common/Queries/SortBuilders/TagReverseSortBuilder.cs +++ b/src/EntityDb.Common/Queries/SortBuilders/TagReverseSortBuilder.cs @@ -1,5 +1,5 @@ using EntityDb.Abstractions.Queries.SortBuilders; -using System; +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; namespace EntityDb.Common.Queries.SortBuilders; @@ -22,8 +22,20 @@ public TSort TagType(bool ascending) return TagSortBuilder.TagType(!ascending); } + [Obsolete("This method will be removed in the future, and may not be supported for all implementations.")] + [ExcludeFromCodeCoverage(Justification = "Obsolete")] public TSort TagProperty(bool ascending, Expression> tagExpression) { return TagSortBuilder.TagProperty(!ascending, tagExpression); } + + public TSort TagLabel(bool ascending) + { + return TagSortBuilder.TagLabel(!ascending); + } + + public TSort TagValue(bool ascending) + { + return TagSortBuilder.TagValue(!ascending); + } } diff --git a/src/EntityDb.Common/Snapshots/ISnapshot.cs b/src/EntityDb.Common/Snapshots/ISnapshot.cs index f2b2820b..2941c86f 100644 --- a/src/EntityDb.Common/Snapshots/ISnapshot.cs +++ b/src/EntityDb.Common/Snapshots/ISnapshot.cs @@ -1,5 +1,4 @@ using EntityDb.Abstractions.ValueObjects; -using System; using System.Diagnostics.CodeAnalysis; namespace EntityDb.Common.Snapshots; diff --git a/src/EntityDb.Common/Snapshots/SnapshotRepositoryWrapper.cs b/src/EntityDb.Common/Snapshots/SnapshotRepositoryWrapper.cs index c4544187..ffee245d 100644 --- a/src/EntityDb.Common/Snapshots/SnapshotRepositoryWrapper.cs +++ b/src/EntityDb.Common/Snapshots/SnapshotRepositoryWrapper.cs @@ -1,9 +1,6 @@ using EntityDb.Abstractions.Snapshots; using EntityDb.Abstractions.ValueObjects; using EntityDb.Common.Disposables; -using System; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.Common.Snapshots; diff --git a/src/EntityDb.Common/Snapshots/TestModeRedisSnapshotRepository.cs b/src/EntityDb.Common/Snapshots/TestModeRedisSnapshotRepository.cs index 9e02e5f8..809b5e95 100644 --- a/src/EntityDb.Common/Snapshots/TestModeRedisSnapshotRepository.cs +++ b/src/EntityDb.Common/Snapshots/TestModeRedisSnapshotRepository.cs @@ -1,8 +1,6 @@ using EntityDb.Abstractions.Snapshots; using EntityDb.Abstractions.ValueObjects; using EntityDb.Common.Disposables; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.Common.Snapshots; diff --git a/src/EntityDb.Common/Snapshots/TestModeSnapshotManager.cs b/src/EntityDb.Common/Snapshots/TestModeSnapshotManager.cs index 174730b1..af984dec 100644 --- a/src/EntityDb.Common/Snapshots/TestModeSnapshotManager.cs +++ b/src/EntityDb.Common/Snapshots/TestModeSnapshotManager.cs @@ -1,9 +1,6 @@ using EntityDb.Abstractions.Snapshots; using EntityDb.Abstractions.ValueObjects; using EntityDb.Common.Disposables; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; namespace EntityDb.Common.Snapshots; diff --git a/src/EntityDb.Common/Snapshots/TestModeSnapshotRepositoryFactory.cs b/src/EntityDb.Common/Snapshots/TestModeSnapshotRepositoryFactory.cs index 03f25cf3..4fe3eb23 100644 --- a/src/EntityDb.Common/Snapshots/TestModeSnapshotRepositoryFactory.cs +++ b/src/EntityDb.Common/Snapshots/TestModeSnapshotRepositoryFactory.cs @@ -1,7 +1,5 @@ using EntityDb.Abstractions.Snapshots; using EntityDb.Common.Disposables; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.Common.Snapshots; diff --git a/src/EntityDb.Common/Snapshots/TryCatchSnapshotRepository.cs b/src/EntityDb.Common/Snapshots/TryCatchSnapshotRepository.cs index 087b143c..fe2ea5c0 100644 --- a/src/EntityDb.Common/Snapshots/TryCatchSnapshotRepository.cs +++ b/src/EntityDb.Common/Snapshots/TryCatchSnapshotRepository.cs @@ -1,8 +1,6 @@ using EntityDb.Abstractions.Snapshots; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using System; -using System.Threading.Tasks; namespace EntityDb.Common.Snapshots; diff --git a/src/EntityDb.Common/Transactions/Builders/TransactionBuilder.cs b/src/EntityDb.Common/Transactions/Builders/TransactionBuilder.cs index 8c88abc4..f8be43df 100644 --- a/src/EntityDb.Common/Transactions/Builders/TransactionBuilder.cs +++ b/src/EntityDb.Common/Transactions/Builders/TransactionBuilder.cs @@ -9,7 +9,6 @@ using EntityDb.Common.Entities; using EntityDb.Common.Exceptions; using EntityDb.Common.Transactions.Steps; -using System.Collections.Generic; using System.Collections.Immutable; namespace EntityDb.Common.Transactions.Builders; diff --git a/src/EntityDb.Common/Transactions/Builders/TransactionBuilderFactory.cs b/src/EntityDb.Common/Transactions/Builders/TransactionBuilderFactory.cs index 52bc58bc..8820f425 100644 --- a/src/EntityDb.Common/Transactions/Builders/TransactionBuilderFactory.cs +++ b/src/EntityDb.Common/Transactions/Builders/TransactionBuilderFactory.cs @@ -2,8 +2,6 @@ using EntityDb.Abstractions.Transactions.Builders; using EntityDb.Abstractions.ValueObjects; using EntityDb.Common.Entities; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.Common.Transactions.Builders; diff --git a/src/EntityDb.Common/Transactions/Subscribers/ProcessorQueues/BufferBlockTransactionQueue.cs b/src/EntityDb.Common/Transactions/Subscribers/ProcessorQueues/BufferBlockTransactionQueue.cs index 428908e5..662ccc10 100644 --- a/src/EntityDb.Common/Transactions/Subscribers/ProcessorQueues/BufferBlockTransactionQueue.cs +++ b/src/EntityDb.Common/Transactions/Subscribers/ProcessorQueues/BufferBlockTransactionQueue.cs @@ -2,10 +2,7 @@ using EntityDb.Common.Transactions.Subscribers.Processors; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -using System; using System.Diagnostics.CodeAnalysis; -using System.Threading; -using System.Threading.Tasks; using System.Threading.Tasks.Dataflow; namespace EntityDb.Common.Transactions.Subscribers.ProcessorQueues; diff --git a/src/EntityDb.Common/Transactions/Subscribers/ProcessorQueues/TestModeTransactionQueue.cs b/src/EntityDb.Common/Transactions/Subscribers/ProcessorQueues/TestModeTransactionQueue.cs index 5fd1e7b0..24ce7a94 100644 --- a/src/EntityDb.Common/Transactions/Subscribers/ProcessorQueues/TestModeTransactionQueue.cs +++ b/src/EntityDb.Common/Transactions/Subscribers/ProcessorQueues/TestModeTransactionQueue.cs @@ -1,6 +1,5 @@ using EntityDb.Abstractions.Transactions; using EntityDb.Common.Transactions.Subscribers.Processors; -using System.Threading.Tasks; namespace EntityDb.Common.Transactions.Subscribers.ProcessorQueues; diff --git a/src/EntityDb.Common/Transactions/Subscribers/Processors/EntitySnapshotTransactionProcessor.cs b/src/EntityDb.Common/Transactions/Subscribers/Processors/EntitySnapshotTransactionProcessor.cs index e6de5eb7..b1016cde 100644 --- a/src/EntityDb.Common/Transactions/Subscribers/Processors/EntitySnapshotTransactionProcessor.cs +++ b/src/EntityDb.Common/Transactions/Subscribers/Processors/EntitySnapshotTransactionProcessor.cs @@ -2,9 +2,6 @@ using EntityDb.Abstractions.Transactions; using EntityDb.Common.Entities; using Microsoft.Extensions.DependencyInjection; -using System; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.Common.Transactions.Subscribers.Processors; diff --git a/src/EntityDb.Common/Transactions/Subscribers/Processors/EntitySnapshotTransactionStepProcessor.cs b/src/EntityDb.Common/Transactions/Subscribers/Processors/EntitySnapshotTransactionStepProcessor.cs index a7894370..9f28ccf2 100644 --- a/src/EntityDb.Common/Transactions/Subscribers/Processors/EntitySnapshotTransactionStepProcessor.cs +++ b/src/EntityDb.Common/Transactions/Subscribers/Processors/EntitySnapshotTransactionStepProcessor.cs @@ -2,8 +2,6 @@ using EntityDb.Abstractions.Transactions; using EntityDb.Abstractions.Transactions.Steps; using EntityDb.Abstractions.ValueObjects; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.Common.Transactions.Subscribers.Processors; diff --git a/src/EntityDb.Common/Transactions/Subscribers/Processors/ITransactionProcessor.cs b/src/EntityDb.Common/Transactions/Subscribers/Processors/ITransactionProcessor.cs index efb82474..09cffee9 100644 --- a/src/EntityDb.Common/Transactions/Subscribers/Processors/ITransactionProcessor.cs +++ b/src/EntityDb.Common/Transactions/Subscribers/Processors/ITransactionProcessor.cs @@ -1,6 +1,4 @@ using EntityDb.Abstractions.Transactions; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.Common.Transactions.Subscribers.Processors; diff --git a/src/EntityDb.Common/Transactions/Subscribers/Processors/ITransactionStepProcessor.cs b/src/EntityDb.Common/Transactions/Subscribers/Processors/ITransactionStepProcessor.cs index ffbedbd3..7a7ff34f 100644 --- a/src/EntityDb.Common/Transactions/Subscribers/Processors/ITransactionStepProcessor.cs +++ b/src/EntityDb.Common/Transactions/Subscribers/Processors/ITransactionStepProcessor.cs @@ -1,7 +1,5 @@ using EntityDb.Abstractions.Transactions; using EntityDb.Abstractions.Transactions.Steps; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.Common.Transactions.Subscribers.Processors; diff --git a/src/EntityDb.Common/Transactions/Subscribers/Processors/ProjectionSnapshotTransactionProcessor.cs b/src/EntityDb.Common/Transactions/Subscribers/Processors/ProjectionSnapshotTransactionProcessor.cs index 468cbbca..0912fec2 100644 --- a/src/EntityDb.Common/Transactions/Subscribers/Processors/ProjectionSnapshotTransactionProcessor.cs +++ b/src/EntityDb.Common/Transactions/Subscribers/Processors/ProjectionSnapshotTransactionProcessor.cs @@ -2,9 +2,6 @@ using EntityDb.Abstractions.Transactions; using EntityDb.Common.Projections; using Microsoft.Extensions.DependencyInjection; -using System; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.Common.Transactions.Subscribers.Processors; diff --git a/src/EntityDb.Common/Transactions/Subscribers/Processors/ProjectionSnapshotTransactionStepProcessor.cs b/src/EntityDb.Common/Transactions/Subscribers/Processors/ProjectionSnapshotTransactionStepProcessor.cs index 69bf4ed2..e433c6d8 100644 --- a/src/EntityDb.Common/Transactions/Subscribers/Processors/ProjectionSnapshotTransactionStepProcessor.cs +++ b/src/EntityDb.Common/Transactions/Subscribers/Processors/ProjectionSnapshotTransactionStepProcessor.cs @@ -4,8 +4,6 @@ using EntityDb.Abstractions.ValueObjects; using EntityDb.Common.Annotations; using EntityDb.Common.Projections; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.Common.Transactions.Subscribers.Processors; diff --git a/src/EntityDb.Common/Transactions/Subscribers/Processors/SnapshotTransactionProcessorBase.cs b/src/EntityDb.Common/Transactions/Subscribers/Processors/SnapshotTransactionProcessorBase.cs index 72350cc0..b08dc096 100644 --- a/src/EntityDb.Common/Transactions/Subscribers/Processors/SnapshotTransactionProcessorBase.cs +++ b/src/EntityDb.Common/Transactions/Subscribers/Processors/SnapshotTransactionProcessorBase.cs @@ -2,9 +2,6 @@ using EntityDb.Abstractions.Transactions; using EntityDb.Abstractions.ValueObjects; using EntityDb.Common.Snapshots; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.Common.Transactions.Subscribers.Processors; diff --git a/src/EntityDb.Common/Transactions/Subscribers/Processors/SnapshotTransactionStepProcessorCache.cs b/src/EntityDb.Common/Transactions/Subscribers/Processors/SnapshotTransactionStepProcessorCache.cs index ef071b92..c1b9d051 100644 --- a/src/EntityDb.Common/Transactions/Subscribers/Processors/SnapshotTransactionStepProcessorCache.cs +++ b/src/EntityDb.Common/Transactions/Subscribers/Processors/SnapshotTransactionStepProcessorCache.cs @@ -1,5 +1,4 @@ using EntityDb.Abstractions.ValueObjects; -using System.Collections.Generic; namespace EntityDb.Common.Transactions.Subscribers.Processors; diff --git a/src/EntityDb.Common/Transactions/TransactionRepositoryWrapper.cs b/src/EntityDb.Common/Transactions/TransactionRepositoryWrapper.cs index 16d1e501..39cf5811 100644 --- a/src/EntityDb.Common/Transactions/TransactionRepositoryWrapper.cs +++ b/src/EntityDb.Common/Transactions/TransactionRepositoryWrapper.cs @@ -5,9 +5,6 @@ using EntityDb.Abstractions.Transactions; using EntityDb.Abstractions.ValueObjects; using EntityDb.Common.Disposables; -using System; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.Common.Transactions; @@ -20,80 +17,88 @@ protected TransactionRepositoryWrapper(ITransactionRepository transactionReposit _transactionRepository = transactionRepository; } - public Task GetTransactionIds(IAgentSignatureQuery agentSignatureQuery, + public IAsyncEnumerable EnumerateTransactionIds(IAgentSignatureQuery agentSignatureQuery, CancellationToken cancellationToken = default) { - return WrapQuery(() => _transactionRepository.GetTransactionIds(agentSignatureQuery, cancellationToken)); + return WrapQuery(() => _transactionRepository.EnumerateTransactionIds(agentSignatureQuery, cancellationToken)); } - public Task GetTransactionIds(ICommandQuery commandQuery, CancellationToken cancellationToken = default) + public IAsyncEnumerable EnumerateTransactionIds(ICommandQuery commandQuery, + CancellationToken cancellationToken = default) { - return WrapQuery(() => _transactionRepository.GetTransactionIds(commandQuery, cancellationToken)); + return WrapQuery(() => _transactionRepository.EnumerateTransactionIds(commandQuery, cancellationToken)); } - public Task GetTransactionIds(ILeaseQuery leaseQuery, CancellationToken cancellationToken = default) + public IAsyncEnumerable EnumerateTransactionIds(ILeaseQuery leaseQuery, + CancellationToken cancellationToken = default) { - return WrapQuery(() => _transactionRepository.GetTransactionIds(leaseQuery, cancellationToken)); + return WrapQuery(() => _transactionRepository.EnumerateTransactionIds(leaseQuery, cancellationToken)); } - public Task GetTransactionIds(ITagQuery tagQuery, CancellationToken cancellationToken = default) + public IAsyncEnumerable EnumerateTransactionIds(ITagQuery tagQuery, + CancellationToken cancellationToken = default) { - return WrapQuery(() => _transactionRepository.GetTransactionIds(tagQuery, cancellationToken)); + return WrapQuery(() => _transactionRepository.EnumerateTransactionIds(tagQuery, cancellationToken)); } - public Task GetEntityIds(IAgentSignatureQuery agentSignatureQuery, + public IAsyncEnumerable EnumerateEntityIds(IAgentSignatureQuery agentSignatureQuery, CancellationToken cancellationToken = default) { - return WrapQuery(() => _transactionRepository.GetEntityIds(agentSignatureQuery, cancellationToken)); + return WrapQuery(() => _transactionRepository.EnumerateEntityIds(agentSignatureQuery, cancellationToken)); } - public Task GetEntityIds(ICommandQuery commandQuery, CancellationToken cancellationToken = default) + public IAsyncEnumerable EnumerateEntityIds(ICommandQuery commandQuery, + CancellationToken cancellationToken = default) { - return WrapQuery(() => _transactionRepository.GetEntityIds(commandQuery, cancellationToken)); + return WrapQuery(() => _transactionRepository.EnumerateEntityIds(commandQuery, cancellationToken)); } - public Task GetEntityIds(ILeaseQuery leaseQuery, CancellationToken cancellationToken = default) + public IAsyncEnumerable EnumerateEntityIds(ILeaseQuery leaseQuery, + CancellationToken cancellationToken = default) { - return WrapQuery(() => _transactionRepository.GetEntityIds(leaseQuery, cancellationToken)); + return WrapQuery(() => _transactionRepository.EnumerateEntityIds(leaseQuery, cancellationToken)); } - public Task GetEntityIds(ITagQuery tagQuery, CancellationToken cancellationToken = default) + public IAsyncEnumerable EnumerateEntityIds(ITagQuery tagQuery, + CancellationToken cancellationToken = default) { - return WrapQuery(() => _transactionRepository.GetEntityIds(tagQuery, cancellationToken)); + return WrapQuery(() => _transactionRepository.EnumerateEntityIds(tagQuery, cancellationToken)); } - public Task GetAgentSignatures(IAgentSignatureQuery agentSignatureQuery, + public IAsyncEnumerable EnumerateAgentSignatures(IAgentSignatureQuery agentSignatureQuery, CancellationToken cancellationToken = default) { - return WrapQuery(() => _transactionRepository.GetAgentSignatures(agentSignatureQuery, cancellationToken)); + return WrapQuery(() => _transactionRepository.EnumerateAgentSignatures(agentSignatureQuery, cancellationToken)); } - public Task GetCommands(ICommandQuery commandQuery, CancellationToken cancellationToken = default) + public IAsyncEnumerable EnumerateCommands(ICommandQuery commandQuery, + CancellationToken cancellationToken = default) { - return WrapQuery(() => _transactionRepository.GetCommands(commandQuery, cancellationToken)); + return WrapQuery(() => _transactionRepository.EnumerateCommands(commandQuery, cancellationToken)); } - public Task GetLeases(ILeaseQuery leaseQuery, CancellationToken cancellationToken = default) + public IAsyncEnumerable EnumerateLeases(ILeaseQuery leaseQuery, + CancellationToken cancellationToken = default) { - return WrapQuery(() => _transactionRepository.GetLeases(leaseQuery, cancellationToken)); + return WrapQuery(() => _transactionRepository.EnumerateLeases(leaseQuery, cancellationToken)); } - public Task GetTags(ITagQuery tagQuery, CancellationToken cancellationToken = default) + public IAsyncEnumerable EnumerateTags(ITagQuery tagQuery, + CancellationToken cancellationToken = default) { - return WrapQuery(() => _transactionRepository.GetTags(tagQuery, cancellationToken)); + return WrapQuery(() => _transactionRepository.EnumerateTags(tagQuery, cancellationToken)); } - public Task[]> GetAnnotatedAgentSignatures(IAgentSignatureQuery agentSignatureQuery, + public IAsyncEnumerable> EnumerateAnnotatedAgentSignatures(IAgentSignatureQuery agentSignatureQuery, CancellationToken cancellationToken = default) { - return WrapQuery(() => - _transactionRepository.GetAnnotatedAgentSignatures(agentSignatureQuery, cancellationToken)); + return WrapQuery(() => _transactionRepository.EnumerateAnnotatedAgentSignatures(agentSignatureQuery, cancellationToken)); } - public Task[]> GetAnnotatedCommands(ICommandQuery commandQuery, + public IAsyncEnumerable> EnumerateAnnotatedCommands(ICommandQuery commandQuery, CancellationToken cancellationToken = default) { - return WrapQuery(() => _transactionRepository.GetAnnotatedCommands(commandQuery, cancellationToken)); + return WrapQuery(() => _transactionRepository.EnumerateAnnotatedCommands(commandQuery, cancellationToken)); } public Task PutTransaction(ITransaction transaction, CancellationToken cancellationToken = default) @@ -106,7 +111,7 @@ public override async ValueTask DisposeAsync() await _transactionRepository.DisposeAsync(); } - protected abstract Task WrapQuery(Func> task); + protected abstract IAsyncEnumerable WrapQuery(Func> enumerable); protected abstract Task WrapCommand(Func> task); } diff --git a/src/EntityDb.Common/Transactions/TryCatchTransactionRepository.cs b/src/EntityDb.Common/Transactions/TryCatchTransactionRepository.cs index a91e45d2..279bcd50 100644 --- a/src/EntityDb.Common/Transactions/TryCatchTransactionRepository.cs +++ b/src/EntityDb.Common/Transactions/TryCatchTransactionRepository.cs @@ -1,8 +1,6 @@ using EntityDb.Abstractions.Transactions; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using System; -using System.Threading.Tasks; namespace EntityDb.Common.Transactions; @@ -19,19 +17,40 @@ ILogger logger _logger = logger; } - protected override async Task WrapQuery(Func> task) + protected override async IAsyncEnumerable WrapQuery(Func> enumerable) { using (_logger.BeginScope("TryCatchId: {TryCatchId}", Guid.NewGuid())) { + IAsyncEnumerator enumerator; + try { - return await task.Invoke(); + enumerator = enumerable.Invoke().GetAsyncEnumerator(); } catch (Exception exception) { _logger.LogError(exception, "The operation cannot be completed"); - return Array.Empty(); + yield break; + } + + while (true) + { + try + { + if (!await enumerator.MoveNextAsync()) + { + yield break; + } + } + catch (Exception exception) + { + _logger.LogError(exception, "The operation cannot be completed"); + + yield break; + } + + yield return enumerator.Current; } } } diff --git a/src/EntityDb.Common/TypeResolvers/DefaultPartialTypeResolver.cs b/src/EntityDb.Common/TypeResolvers/DefaultPartialTypeResolver.cs index 14c66da9..4c5fd840 100644 --- a/src/EntityDb.Common/TypeResolvers/DefaultPartialTypeResolver.cs +++ b/src/EntityDb.Common/TypeResolvers/DefaultPartialTypeResolver.cs @@ -1,5 +1,4 @@ using EntityDb.Common.Envelopes; -using System; using System.Diagnostics.CodeAnalysis; using System.Reflection; diff --git a/src/EntityDb.Common/TypeResolvers/IPartialTypeResolver.cs b/src/EntityDb.Common/TypeResolvers/IPartialTypeResolver.cs index 9531b8b8..ea25634c 100644 --- a/src/EntityDb.Common/TypeResolvers/IPartialTypeResolver.cs +++ b/src/EntityDb.Common/TypeResolvers/IPartialTypeResolver.cs @@ -1,5 +1,4 @@ using EntityDb.Common.Envelopes; -using System; using System.Diagnostics.CodeAnalysis; namespace EntityDb.Common.TypeResolvers; diff --git a/src/EntityDb.Common/TypeResolvers/ITypeResolver.cs b/src/EntityDb.Common/TypeResolvers/ITypeResolver.cs index 48d055de..0ae418e9 100644 --- a/src/EntityDb.Common/TypeResolvers/ITypeResolver.cs +++ b/src/EntityDb.Common/TypeResolvers/ITypeResolver.cs @@ -1,5 +1,4 @@ using EntityDb.Common.Envelopes; -using System; namespace EntityDb.Common.TypeResolvers; diff --git a/src/EntityDb.Common/TypeResolvers/LifoTypeResolver.cs b/src/EntityDb.Common/TypeResolvers/LifoTypeResolver.cs index bd73d453..5859bcda 100644 --- a/src/EntityDb.Common/TypeResolvers/LifoTypeResolver.cs +++ b/src/EntityDb.Common/TypeResolvers/LifoTypeResolver.cs @@ -1,9 +1,6 @@ using EntityDb.Common.Envelopes; using EntityDb.Common.Exceptions; using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.Linq; namespace EntityDb.Common.TypeResolvers; diff --git a/src/EntityDb.Common/TypeResolvers/MemberInfoNamePartialTypeResolver.cs b/src/EntityDb.Common/TypeResolvers/MemberInfoNamePartialTypeResolver.cs index bc189c3f..59fa5351 100644 --- a/src/EntityDb.Common/TypeResolvers/MemberInfoNamePartialTypeResolver.cs +++ b/src/EntityDb.Common/TypeResolvers/MemberInfoNamePartialTypeResolver.cs @@ -1,8 +1,5 @@ using EntityDb.Common.Envelopes; -using System; -using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.Linq; namespace EntityDb.Common.TypeResolvers; diff --git a/src/EntityDb.Common/packages.lock.json b/src/EntityDb.Common/packages.lock.json index a36eeb96..7cf0e02d 100644 --- a/src/EntityDb.Common/packages.lock.json +++ b/src/EntityDb.Common/packages.lock.json @@ -2,8 +2,25 @@ "version": 1, "dependencies": { "net6.0": { + "System.Linq.Async": { + "type": "Direct", + "requested": "[6.0.1, )", + "resolved": "6.0.1", + "contentHash": "0YhHcaroWpQ9UCot3Pizah7ryAzQhNvobLMSxeDIGmnXfkQn8u5owvpOH0K6EVB+z9L7u6Cc4W17Br/+jyttEQ==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "6.0.0" + } + }, + "Microsoft.Bcl.AsyncInterfaces": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==" + }, "entitydb.abstractions": { - "type": "Project" + "type": "Project", + "dependencies": { + "System.Linq.Async": "6.0.1" + } } } } diff --git a/src/EntityDb.EventStore/packages.lock.json b/src/EntityDb.EventStore/packages.lock.json new file mode 100644 index 00000000..db3b32d0 --- /dev/null +++ b/src/EntityDb.EventStore/packages.lock.json @@ -0,0 +1,748 @@ +{ + "version": 1, + "dependencies": { + "net6.0": { + "EventStore.Client": { + "type": "Direct", + "requested": "[21.2.2, )", + "resolved": "21.2.2", + "contentHash": "3xLQEOkpOMCm5/2Spk6mFwqFBowYw9pA9Np3K+YVF0yMh2KCQGW/21iV6CdT9XRtB+CzoKDYDhaZlsvaFpfbPQ==", + "dependencies": { + "Newtonsoft.Json": "11.0.2", + "System.Net.Http": "4.3.4", + "protobuf-net": "2.4.0" + } + }, + "EventStore.Client.Grpc.Streams": { + "type": "Direct", + "requested": "[22.0.0, )", + "resolved": "22.0.0", + "contentHash": "LNZxzw3nse5kp7rr5aJS65OR0zmhdEatYx12miy7W8Bno8vqEaGYFtMjDUsfuC5JPw2VwUw9LW9KypfOjpf/Wg==", + "dependencies": { + "EventStore.Client.Grpc": "22.0.0" + } + }, + "System.Linq.Async": { + "type": "Direct", + "requested": "[6.0.1, )", + "resolved": "6.0.1", + "contentHash": "0YhHcaroWpQ9UCot3Pizah7ryAzQhNvobLMSxeDIGmnXfkQn8u5owvpOH0K6EVB+z9L7u6Cc4W17Br/+jyttEQ==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "6.0.0" + } + }, + "EventStore.Client.Grpc": { + "type": "Transitive", + "resolved": "22.0.0", + "contentHash": "DwPcpRkKRDX1c7wjCqbeGFXF2vsqWu+O1f3Y/iNCf+07nzP8N04/L/5LUheuKeyQogoh3t+I4koAOUitUdsSQw==", + "dependencies": { + "Google.Protobuf": "3.15.0", + "Grpc.Net.Client": "2.40.0", + "Microsoft.Extensions.Logging": "5.0.0", + "System.Linq.Async": "5.0.0" + } + }, + "Google.Protobuf": { + "type": "Transitive", + "resolved": "3.15.0", + "contentHash": "2na7LsYrtxkEQaVCNjaafBzVu4IJ4U4+dwwBazK8oUkpDiIFjO0GkyTc+IbStx4xNVAV4EqHl+qp2uegFgFiiA==", + "dependencies": { + "System.Memory": "4.5.3", + "System.Runtime.CompilerServices.Unsafe": "4.5.2" + } + }, + "Grpc.Core.Api": { + "type": "Transitive", + "resolved": "2.40.0", + "contentHash": "Ig3ioHBMDl8jZzPRU+t8GPpgDBYkjwupHzSVswwrsUVZdO5SThmYY4fHftNC1rMCjsjVvUMQ/o1NCf1CT4Y+rA==", + "dependencies": { + "System.Memory": "4.5.3" + } + }, + "Grpc.Net.Client": { + "type": "Transitive", + "resolved": "2.40.0", + "contentHash": "+Z+onJ5jOLwKR41wROs+I1Bo6+NKT9ov/moXZCi9vH7aDRVQuqhmfALoxWdsNUNO9Bl3A/VzmfPB2jxZB4B1WQ==", + "dependencies": { + "Grpc.Net.Common": "2.40.0", + "Microsoft.Extensions.Logging.Abstractions": "3.0.3" + } + }, + "Grpc.Net.Common": { + "type": "Transitive", + "resolved": "2.40.0", + "contentHash": "nj5XotYmzAT4UlGyOK6xWacPp2nODupQvlbeA2qqu9F47BIr+vze6+psJ9gSgED2HeTVBXuc+vdKrUXzk0ErMQ==", + "dependencies": { + "Grpc.Core.Api": "2.40.0" + } + }, + "Microsoft.Bcl.AsyncInterfaces": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==" + }, + "Microsoft.Extensions.DependencyInjection": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "Rc2kb/p3Ze6cP6rhFC3PJRdWGbLvSHZc0ev7YlyeU6FmHciDMLrhoVoTUEzKPhN5ZjFgKF1Cf5fOz8mCMIkvpA==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "5.0.0" + } + }, + "Microsoft.Extensions.DependencyInjection.Abstractions": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "ORj7Zh81gC69TyvmcUm9tSzytcy8AVousi+IVRAI8nLieQjOFryRusSFh7+aLk16FN9pQNqJAiMd7BTKINK0kA==" + }, + "Microsoft.Extensions.Logging": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "MgOwK6tPzB6YNH21wssJcw/2MKwee8b2gI7SllYfn6rvTpIrVvVS5HAjSU2vqSku1fwqRvWP0MdIi14qjd93Aw==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection": "5.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "5.0.0", + "Microsoft.Extensions.Logging.Abstractions": "5.0.0", + "Microsoft.Extensions.Options": "5.0.0" + } + }, + "Microsoft.Extensions.Logging.Abstractions": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "NxP6ahFcBnnSfwNBi2KH2Oz8Xl5Sm2krjId/jRR3I7teFphwiUoUeZPwTNA21EX+5PtjqmyAvKaOeBXcJjcH/w==" + }, + "Microsoft.Extensions.Options": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "CBvR92TCJ5uBIdd9/HzDSrxYak+0W/3+yxrNg8Qm6Bmrkh5L+nu6m3WeazQehcZ5q1/6dDA7J5YdQjim0165zg==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "5.0.0", + "Microsoft.Extensions.Primitives": "5.0.0" + } + }, + "Microsoft.Extensions.Primitives": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "cI/VWn9G1fghXrNDagX9nYaaB/nokkZn0HYAawGaELQrl8InSezfe9OnfPZLcJq3esXxygh3hkq2c3qoV3SDyQ==" + }, + "Microsoft.NETCore.Platforms": { + "type": "Transitive", + "resolved": "2.1.0", + "contentHash": "ok+RPAtESz/9MUXeIEz6Lv5XAGQsaNmEYXMsgVALj4D7kqC8gveKWXWXbufLySR2fWrwZf8smyN5RmHu0e4BHA==" + }, + "Microsoft.NETCore.Targets": { + "type": "Transitive", + "resolved": "1.1.0", + "contentHash": "aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg==" + }, + "Newtonsoft.Json": { + "type": "Transitive", + "resolved": "11.0.2", + "contentHash": "IvJe1pj7JHEsP8B8J8DwlMEx8UInrs/x+9oVY+oCD13jpLu4JbJU2WCIsMRn5C4yW9+DgkaO8uiVE5VHKjpmdQ==" + }, + "protobuf-net": { + "type": "Transitive", + "resolved": "2.4.0", + "contentHash": "j37MD1p1s9NdX8P5+IaY2J9p2382xiL1VP3mxYu0g+G/kf2YM2grFa1jJPO+0WDJNl1XhNPO0Q5yBEcbX77hBQ==", + "dependencies": { + "System.ServiceModel.Primitives": "4.5.3" + } + }, + "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "7VSGO0URRKoMEAq0Sc9cRz8mb6zbyx/BZDEWhgPdzzpmFhkam3fJ1DAGWFXBI4nGlma+uPKpfuMQP5LXRnOH5g==" + }, + "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "0oAaTAm6e2oVH+/Zttt0cuhGaePQYKII1dY8iaqP7CvOpVKgLybKRFvQjXR2LtxXOXTVPNv14j0ot8uV+HrUmw==" + }, + "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "G24ibsCNi5Kbz0oXWynBoRgtGvsw5ZSVEWjv13/KiCAM8C6wz9zzcCniMeQFIkJ2tasjo2kXlvlBZhplL51kGg==" + }, + "runtime.native.System": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "c/qWt2LieNZIj1jGnVNsE2Kl23Ya2aSTBuXMD6V7k9KWr6l16Tqdwq+hJScEpWER9753NWC8h96PaVNY5Ld7Jw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0" + } + }, + "runtime.native.System.Net.Http": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "ZVuZJqnnegJhd2k/PtAbbIcZ3aZeITq3sj06oKfMBSfphW3HDmk/t4ObvbOk/JA/swGR0LNqMksAh/f7gpTROg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0" + } + }, + "runtime.native.System.Security.Cryptography.Apple": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "DloMk88juo0OuOWr56QG7MNchmafTLYWvABy36izkrLI5VledI0rq28KGs1i9wbpeT9NPQrx/wTf8U2vazqQ3Q==", + "dependencies": { + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple": "4.3.0" + } + }, + "runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "QR1OwtwehHxSeQvZKXe+iSd+d3XZNkEcuWMFYa2i0aG1l+lR739HPicKMlTbJst3spmeekDVBUS7SeS26s4U/g==", + "dependencies": { + "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", + "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", + "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", + "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", + "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", + "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", + "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", + "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", + "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2" + } + }, + "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "I+GNKGg2xCHueRd1m9PzeEW7WLbNNLznmTuEi8/vZX71HudUbx1UTwlGkiwMri7JLl8hGaIAWnA/GONhu+LOyQ==" + }, + "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "1Z3TAq1ytS1IBRtPXJvEUZdVsfWfeNEhBkbiOCGEl9wwAfsjP2lz3ZFDx5tq8p60/EqbS0HItG5piHuB71RjoA==" + }, + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "kVXCuMTrTlxq4XOOMAysuNwsXWpYeboGddNGpIgNSZmv1b6r/s/DPk0fYMB7Q5Qo4bY68o48jt4T4y5BVecbCQ==" + }, + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "6mU/cVmmHtQiDXhnzUImxIcDL48GbTk+TsptXyJA+MIOG9LRjPoAQC/qBFB7X+UNyK86bmvGwC8t+M66wsYC8w==" + }, + "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "vjwG0GGcTW/PPg6KVud8F9GLWYuAV1rrw1BKAqY0oh4jcUqg15oYF1+qkGR2x2ZHM4DQnWKQ7cJgYbfncz/lYg==" + }, + "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "7KMFpTkHC/zoExs+PwP8jDCWcrK9H6L7soowT80CUx3e+nxP/AFnq0AQAW5W76z2WYbLAYCRyPfwYFG6zkvQRw==" + }, + "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "xrlmRCnKZJLHxyyLIqkZjNXqgxnKdZxfItrPkjI+6pkRo5lHX8YvSZlWrSI5AVwLMi4HbNWP7064hcAWeZKp5w==" + }, + "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "leXiwfiIkW7Gmn7cgnNcdtNAU70SjmKW3jxGj1iKHOvdn0zRWsgv/l2OJUO5zdGdiv2VRFnAsxxhDgMzofPdWg==" + }, + "System.Collections": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "3Dcj85/TBdVpL5Zr+gEEBUuFe2icOnLalmEh9hfck1PTYbbyWuZgh4fmm2ysCLTrqLQw6t3TgTyJ+VLp+Qb+Lw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Collections.Concurrent": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "ztl69Xp0Y/UXCL+3v3tEU+lIy+bvjKNUmopn1wep/a291pVPK7dxBd6T7WnlQqRog+d1a/hSsgRsmFnIBKTPLQ==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Diagnostics.Tracing": "4.3.0", + "System.Globalization": "4.3.0", + "System.Reflection": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.Diagnostics.Debug": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "ZUhUOdqmaG5Jk3Xdb8xi5kIyQYAA4PnTNlHx1mu9ZY3qv4ELIdKbnL/akbGaKi2RnNUWaZsAs31rvzFdewTj2g==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Diagnostics.DiagnosticSource": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "tD6kosZnTAGdrEa0tZSuFyunMbt/5KYDnHdndJYGqZoNy00XVXyACd5d6KnE1YgYv3ne2CjtAfNXo/fwEhnKUA==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Tracing": "4.3.0", + "System.Reflection": "4.3.0", + "System.Runtime": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "System.Diagnostics.Tracing": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "rswfv0f/Cqkh78rA5S8eN8Neocz234+emGCtTF3lxPY96F+mmmUen6tbn0glN6PMvlKQb9bPAY5e9u7fgPTkKw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Globalization": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "kYdVd2f2PAdFGblzFswE4hkNANJBKRmsfa2X5LG2AcWE1c7/4t0pYae1L8vfZ5xvE2nK/R9JprtToA61OSHWIg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Globalization.Calendars": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "GUlBtdOWT4LTV3I+9/PJW+56AnnChTaOqqTLFtdmype/L500M2LIyXgmtd9X2P2VOkmJd5c67H5SaC2QcL1bFA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Globalization": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Globalization.Extensions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "FhKmdR6MPG+pxow6wGtNAWdZh7noIOpdD5TwQ3CprzgIE1bBBoim0vbR1+AWsWjQmU7zXHgQo4TWSP6lCeiWcQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.Globalization": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.InteropServices": "4.3.0" + } + }, + "System.IO": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "3qjaHvxQPDpSOYICjUoTsmoq5u6QJAFRUITgeT/4gqkF1bajbSmb1kwSxEA8AHlofqgcKJcM8udgieRNhaJ5Cg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.IO.FileSystem": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "3wEMARTnuio+ulnvi+hkRNROYwa1kylvYahhcLk4HSoVdl+xxTFVeVlYOfLwrDPImGls0mDqbMhrza8qnWPTdA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.IO": "4.3.0", + "System.IO.FileSystem.Primitives": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.IO.FileSystem.Primitives": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "6QOb2XFLch7bEc4lIcJH49nJN2HV+OC3fHDgsLVsBVBk3Y4hFAnOBGzJ2lUu7CyDDFo9IBWkSsnbkT6IBwwiMw==", + "dependencies": { + "System.Runtime": "4.3.0" + } + }, + "System.Linq": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "5DbqIUpsDp0dFftytzuMmc0oeMdQwjcP/EWxsksIz/w1TcFRkZ3yKKz0PqiYFMmEwPSWw+qNVqD7PJ889JzHbw==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0" + } + }, + "System.Memory": { + "type": "Transitive", + "resolved": "4.5.3", + "contentHash": "3oDzvc/zzetpTKWMShs1AADwZjQ/36HnsufHRPcOjyRAAMLDlu2iD33MBI2opxnezcVUtXyqDXXjoFMOU9c7SA==" + }, + "System.Net.Http": { + "type": "Transitive", + "resolved": "4.3.4", + "contentHash": "aOa2d51SEbmM+H+Csw7yJOuNZoHkrP2XnAurye5HWYgGVVU54YZDvsLUYRv6h18X3sPnjNCANmN7ZhIPiqMcjA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.1", + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Diagnostics.DiagnosticSource": "4.3.0", + "System.Diagnostics.Tracing": "4.3.0", + "System.Globalization": "4.3.0", + "System.Globalization.Extensions": "4.3.0", + "System.IO": "4.3.0", + "System.IO.FileSystem": "4.3.0", + "System.Net.Primitives": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Security.Cryptography.Algorithms": "4.3.0", + "System.Security.Cryptography.Encoding": "4.3.0", + "System.Security.Cryptography.OpenSsl": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Security.Cryptography.X509Certificates": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0", + "runtime.native.System": "4.3.0", + "runtime.native.System.Net.Http": "4.3.0", + "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2" + } + }, + "System.Net.Primitives": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "qOu+hDwFwoZPbzPvwut2qATe3ygjeQBDQj91xlsaqGFQUI5i4ZnZb8yyQuLGpDGivEPIt8EJkd1BVzVoP31FXA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0", + "System.Runtime.Handles": "4.3.0" + } + }, + "System.Private.ServiceModel": { + "type": "Transitive", + "resolved": "4.5.3", + "contentHash": "ancrQgJagx+yC4SZbuE+eShiEAUIF0E1d21TRSoy1C/rTwafAVcBr/fKibkq5TQzyy9uNil2tx2/iaUxsy0S9g==", + "dependencies": { + "Microsoft.NETCore.Platforms": "2.1.0", + "System.Reflection.DispatchProxy": "4.5.0", + "System.Security.Principal.Windows": "4.5.0" + } + }, + "System.Reflection": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "KMiAFoW7MfJGa9nDFNcfu+FpEdiHpWgTcS2HdMpDvt9saK3y/G4GwprPyzqjFH9NTaGPQeWNHU+iDlDILj96aQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.IO": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.DispatchProxy": { + "type": "Transitive", + "resolved": "4.5.0", + "contentHash": "+UW1hq11TNSeb+16rIk8hRQ02o339NFyzMc4ma/FqmxBzM30l1c2IherBB4ld1MNcenS48fz8tbt50OW4rVULA==" + }, + "System.Reflection.Primitives": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "5RXItQz5As4xN2/YUDxdpsEkMhvw3e6aNveFXUn4Hl/udNTCNhnKp8lT9fnc3MhvGKh1baak5CovpuQUXHAlIA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Resources.ResourceManager": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "/zrcPkkWdZmI4F92gL/TPumP98AVDu/Wxr3CSJGQQ+XN6wbRZcyfSKVoPo17ilb3iOr0cCRqJInGwNMolqhS8A==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Globalization": "4.3.0", + "System.Reflection": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Runtime": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "JufQi0vPQ0xGnAczR13AUFglDyVYt4Kqnz1AZaiKZ5+GICq0/1MH/mO/eAJHt/mHW1zjKBJd7kV26SrxddAhiw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0" + } + }, + "System.Runtime.CompilerServices.Unsafe": { + "type": "Transitive", + "resolved": "4.5.2", + "contentHash": "wprSFgext8cwqymChhrBLu62LMg/1u92bU+VOwyfBimSPVFXtsNqEWC92Pf9ofzJFlk4IHmJA75EDJn1b2goAQ==" + }, + "System.Runtime.Extensions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "guW0uK0fn5fcJJ1tJVXYd7/1h5F+pea1r7FLSOz/f8vPEqbR2ZAknuRDvTQ8PzAilDveOxNjSfr0CHfIQfFk8g==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Runtime.Handles": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "OKiSUN7DmTWeYb3l51A7EYaeNMnvxwE249YtZz7yooT4gOZhmTjIn48KgSsw2k2lYdLgTKNJw/ZIfSElwDRVgg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Runtime.InteropServices": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "uv1ynXqiMK8mp1GM3jDqPCFN66eJ5w5XNomaK2XD+TuCroNTLFGeZ+WCmBMcBDyTFKou3P6cR6J/QsaqDp7fGQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Reflection": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Handles": "4.3.0" + } + }, + "System.Runtime.Numerics": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "yMH+MfdzHjy17l2KESnPiF2dwq7T+xLnSJar7slyimAkUh/gTrS9/UQOtv7xarskJ2/XDSNvfLGOBQPjL7PaHQ==", + "dependencies": { + "System.Globalization": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0" + } + }, + "System.Security.Cryptography.Algorithms": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "W1kd2Y8mYSCgc3ULTAZ0hOP2dSdG5YauTb1089T0/kRcN2MpSAW1izOFROrJgxSlMn3ArsgHXagigyi+ibhevg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.Collections": "4.3.0", + "System.IO": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Runtime.Numerics": "4.3.0", + "System.Security.Cryptography.Encoding": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Text.Encoding": "4.3.0", + "runtime.native.System.Security.Cryptography.Apple": "4.3.0", + "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" + } + }, + "System.Security.Cryptography.Cng": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "03idZOqFlsKRL4W+LuCpJ6dBYDUWReug6lZjBa3uJWnk5sPCUXckocevTaUA8iT/MFSrY/2HXkOt753xQ/cf8g==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.IO": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Security.Cryptography.Algorithms": "4.3.0", + "System.Security.Cryptography.Encoding": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Text.Encoding": "4.3.0" + } + }, + "System.Security.Cryptography.Csp": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "X4s/FCkEUnRGnwR3aSfVIkldBmtURMhmexALNTwpjklzxWU7yjMk7GHLKOZTNkgnWnE0q7+BCf9N2LVRWxewaA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.IO": "4.3.0", + "System.Reflection": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Security.Cryptography.Algorithms": "4.3.0", + "System.Security.Cryptography.Encoding": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "System.Security.Cryptography.Encoding": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "1DEWjZZly9ae9C79vFwqaO5kaOlI5q+3/55ohmq/7dpDyDfc8lYe7YVxJUZ5MF/NtbkRjwFRo14yM4OEo9EmDw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.Collections": "4.3.0", + "System.Collections.Concurrent": "4.3.0", + "System.Linq": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Text.Encoding": "4.3.0", + "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" + } + }, + "System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "h4CEgOgv5PKVF/HwaHzJRiVboL2THYCou97zpmhjghx5frc7fIvlkY1jL+lnIQyChrJDMNEXS6r7byGif8Cy4w==", + "dependencies": { + "System.Collections": "4.3.0", + "System.IO": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Runtime.Numerics": "4.3.0", + "System.Security.Cryptography.Algorithms": "4.3.0", + "System.Security.Cryptography.Encoding": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Text.Encoding": "4.3.0", + "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" + } + }, + "System.Security.Cryptography.Primitives": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "7bDIyVFNL/xKeFHjhobUAQqSpJq9YTOpbEs6mR233Et01STBMXNAc/V+BM6dwYGc95gVh/Zf+iVXWzj3mE8DWg==", + "dependencies": { + "System.Diagnostics.Debug": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.Security.Cryptography.X509Certificates": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "t2Tmu6Y2NtJ2um0RtcuhP7ZdNNxXEgUm2JeoA/0NvlMjAhKCnM1NX07TDl3244mVp3QU6LPEhT3HTtH1uF7IYw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Globalization": "4.3.0", + "System.Globalization.Calendars": "4.3.0", + "System.IO": "4.3.0", + "System.IO.FileSystem": "4.3.0", + "System.IO.FileSystem.Primitives": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Runtime.Numerics": "4.3.0", + "System.Security.Cryptography.Algorithms": "4.3.0", + "System.Security.Cryptography.Cng": "4.3.0", + "System.Security.Cryptography.Csp": "4.3.0", + "System.Security.Cryptography.Encoding": "4.3.0", + "System.Security.Cryptography.OpenSsl": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading": "4.3.0", + "runtime.native.System": "4.3.0", + "runtime.native.System.Net.Http": "4.3.0", + "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" + } + }, + "System.Security.Principal.Windows": { + "type": "Transitive", + "resolved": "4.5.0", + "contentHash": "U77HfRXlZlOeIXd//Yoj6Jnk8AXlbeisf1oq1os+hxOGVnuG+lGSfGqTwTZBoORFF6j/0q7HXIl8cqwQ9aUGqQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "2.0.0" + } + }, + "System.ServiceModel.Primitives": { + "type": "Transitive", + "resolved": "4.5.3", + "contentHash": "Wc9Hgg4Cmqi416zvEgq2sW1YYCGuhwWzspDclJWlFZqY6EGhFUPZU+kVpl5z9kAgrSOQP7/Uiik+PtSQtmq+5A==", + "dependencies": { + "System.Private.ServiceModel": "4.5.3" + } + }, + "System.Text.Encoding": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "BiIg+KWaSDOITze6jGQynxg64naAPtqGHBwDrLaCtixsa5bKiR8dpPOHA7ge3C0JJQizJE+sfkz1wV+BAKAYZw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Threading": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "VkUS0kOBcUf3Wwm0TSbrevDDZ6BlM+b/HRiapRFWjM5O0NS0LviG0glKmFK+hhPDd1XFeSdU1GmlLhb2CoVpIw==", + "dependencies": { + "System.Runtime": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.Threading.Tasks": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "LbSxKEdOUhVe8BezB/9uOGGppt+nZf6e1VFyw6v3DN6lqitm0OSn2uXMOdtP0M3W4iMcqcivm2J6UgqiwwnXiA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "entitydb.abstractions": { + "type": "Project", + "dependencies": { + "System.Linq.Async": "6.0.1" + } + }, + "entitydb.common": { + "type": "Project", + "dependencies": { + "EntityDb.Abstractions": "1.0.0", + "System.Linq.Async": "6.0.1" + } + } + } + } +} \ No newline at end of file diff --git a/src/EntityDb.InMemory/Sessions/IInMemorySession.cs b/src/EntityDb.InMemory/Sessions/IInMemorySession.cs index 0beb47e9..874ce661 100644 --- a/src/EntityDb.InMemory/Sessions/IInMemorySession.cs +++ b/src/EntityDb.InMemory/Sessions/IInMemorySession.cs @@ -1,6 +1,4 @@ using EntityDb.Abstractions.ValueObjects; -using System.Collections.Generic; -using System.Threading.Tasks; namespace EntityDb.InMemory.Sessions; diff --git a/src/EntityDb.InMemory/Sessions/InMemorySession.cs b/src/EntityDb.InMemory/Sessions/InMemorySession.cs index f79d5bdf..ce19a751 100644 --- a/src/EntityDb.InMemory/Sessions/InMemorySession.cs +++ b/src/EntityDb.InMemory/Sessions/InMemorySession.cs @@ -1,8 +1,5 @@ using EntityDb.Abstractions.ValueObjects; using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; namespace EntityDb.InMemory.Sessions; diff --git a/src/EntityDb.InMemory/Sessions/ReadOnlyInMemorySession.cs b/src/EntityDb.InMemory/Sessions/ReadOnlyInMemorySession.cs index 1811f4dc..5c39e06b 100644 --- a/src/EntityDb.InMemory/Sessions/ReadOnlyInMemorySession.cs +++ b/src/EntityDb.InMemory/Sessions/ReadOnlyInMemorySession.cs @@ -1,7 +1,5 @@ using EntityDb.Abstractions.ValueObjects; using EntityDb.Common.Exceptions; -using System.Collections.Generic; -using System.Threading.Tasks; namespace EntityDb.InMemory.Sessions; diff --git a/src/EntityDb.InMemory/Snapshots/InMemorySnapshotRepository.cs b/src/EntityDb.InMemory/Snapshots/InMemorySnapshotRepository.cs index c8c03b50..9c3c151e 100644 --- a/src/EntityDb.InMemory/Snapshots/InMemorySnapshotRepository.cs +++ b/src/EntityDb.InMemory/Snapshots/InMemorySnapshotRepository.cs @@ -2,8 +2,6 @@ using EntityDb.Abstractions.ValueObjects; using EntityDb.Common.Disposables; using EntityDb.InMemory.Sessions; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.InMemory.Snapshots; diff --git a/src/EntityDb.InMemory/Snapshots/InMemorySnapshotRepositoryFactory.cs b/src/EntityDb.InMemory/Snapshots/InMemorySnapshotRepositoryFactory.cs index 169d494e..38ea4924 100644 --- a/src/EntityDb.InMemory/Snapshots/InMemorySnapshotRepositoryFactory.cs +++ b/src/EntityDb.InMemory/Snapshots/InMemorySnapshotRepositoryFactory.cs @@ -3,9 +3,6 @@ using EntityDb.Common.Snapshots; using EntityDb.InMemory.Sessions; using Microsoft.Extensions.Options; -using System; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.InMemory.Snapshots; diff --git a/src/EntityDb.InMemory/packages.lock.json b/src/EntityDb.InMemory/packages.lock.json index 8c9a5d5c..030ca5af 100644 --- a/src/EntityDb.InMemory/packages.lock.json +++ b/src/EntityDb.InMemory/packages.lock.json @@ -2,13 +2,31 @@ "version": 1, "dependencies": { "net6.0": { + "System.Linq.Async": { + "type": "Direct", + "requested": "[6.0.1, )", + "resolved": "6.0.1", + "contentHash": "0YhHcaroWpQ9UCot3Pizah7ryAzQhNvobLMSxeDIGmnXfkQn8u5owvpOH0K6EVB+z9L7u6Cc4W17Br/+jyttEQ==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "6.0.0" + } + }, + "Microsoft.Bcl.AsyncInterfaces": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==" + }, "entitydb.abstractions": { - "type": "Project" + "type": "Project", + "dependencies": { + "System.Linq.Async": "6.0.1" + } }, "entitydb.common": { "type": "Project", "dependencies": { - "EntityDb.Abstractions": "1.0.0" + "EntityDb.Abstractions": "1.0.0", + "System.Linq.Async": "6.0.1" } } } diff --git a/src/EntityDb.Redis/Converters/EnvelopeHeadersConverter.cs b/src/EntityDb.Json/Converters/EnvelopeHeadersConverter.cs similarity index 89% rename from src/EntityDb.Redis/Converters/EnvelopeHeadersConverter.cs rename to src/EntityDb.Json/Converters/EnvelopeHeadersConverter.cs index 37b5b9c9..79fdc811 100644 --- a/src/EntityDb.Redis/Converters/EnvelopeHeadersConverter.cs +++ b/src/EntityDb.Json/Converters/EnvelopeHeadersConverter.cs @@ -1,51 +1,49 @@ -using EntityDb.Common.Envelopes; -using System; -using System.Collections.Generic; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace EntityDb.Redis.Converters; - -internal class EnvelopeHeadersConverter : JsonConverter -{ - public override EnvelopeHeaders Read - ( - ref Utf8JsonReader reader, - Type typeToConvert, - JsonSerializerOptions options - ) - { - var value = new Dictionary(); - - while (reader.Read() && reader.TokenType == JsonTokenType.PropertyName) - { - var propertyName = reader.GetString()!; - - reader.Read(); - - var propertyValue = reader.GetString()!; - - value.Add(propertyName, propertyValue); - } - - return new EnvelopeHeaders(value); - } - - public override void Write - ( - Utf8JsonWriter writer, - EnvelopeHeaders envelopeHeaders, - JsonSerializerOptions options - ) - { - writer.WriteStartObject(); - - foreach (var (propertyName, propertyValue) in envelopeHeaders.Value) - { - writer.WritePropertyName(propertyName); - writer.WriteStringValue(propertyValue); - } - - writer.WriteEndObject(); - } -} +using EntityDb.Common.Envelopes; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace EntityDb.Json.Converters; + +internal class EnvelopeHeadersConverter : JsonConverter +{ + public override EnvelopeHeaders Read + ( + ref Utf8JsonReader reader, + Type typeToConvert, + JsonSerializerOptions options + ) + { + var value = new Dictionary(); + + while (reader.Read() && reader.TokenType == JsonTokenType.PropertyName) + { + var propertyName = reader.GetString()!; + + reader.Read(); + + var propertyValue = reader.GetString()!; + + value.Add(propertyName, propertyValue); + } + + return new EnvelopeHeaders(value); + } + + public override void Write + ( + Utf8JsonWriter writer, + EnvelopeHeaders envelopeHeaders, + JsonSerializerOptions options + ) + { + writer.WriteStartObject(); + + foreach (var (propertyName, propertyValue) in envelopeHeaders.Value) + { + writer.WritePropertyName(propertyName); + writer.WriteStringValue(propertyValue); + } + + writer.WriteEndObject(); + } +} diff --git a/src/EntityDb.Redis/Converters/IdConverter.cs b/src/EntityDb.Json/Converters/IdConverter.cs similarity index 89% rename from src/EntityDb.Redis/Converters/IdConverter.cs rename to src/EntityDb.Json/Converters/IdConverter.cs index 197c18a9..2da79af2 100644 --- a/src/EntityDb.Redis/Converters/IdConverter.cs +++ b/src/EntityDb.Json/Converters/IdConverter.cs @@ -1,40 +1,39 @@ -using EntityDb.Abstractions.ValueObjects; -using System; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace EntityDb.Redis.Converters; - -internal class IdConverter : JsonConverter -{ - public override Id Read - ( - ref Utf8JsonReader reader, - Type typeToConvert, - JsonSerializerOptions options - ) - { - if (reader.TokenType != JsonTokenType.String) - { - throw new NotSupportedException(); - } - - var stringValue = reader.GetString(); - - var guidValue = Guid.Parse(stringValue!); - - return new Id(guidValue); - } - - public override void Write - ( - Utf8JsonWriter writer, - Id id, - JsonSerializerOptions options - ) - { - var stringValue = id.Value.ToString(); - - writer.WriteStringValue(stringValue); - } -} +using EntityDb.Abstractions.ValueObjects; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace EntityDb.Json.Converters; + +internal class IdConverter : JsonConverter +{ + public override Id Read + ( + ref Utf8JsonReader reader, + Type typeToConvert, + JsonSerializerOptions options + ) + { + if (reader.TokenType != JsonTokenType.String) + { + throw new NotSupportedException(); + } + + var stringValue = reader.GetString(); + + var guidValue = Guid.Parse(stringValue!); + + return new Id(guidValue); + } + + public override void Write + ( + Utf8JsonWriter writer, + Id id, + JsonSerializerOptions options + ) + { + var stringValue = id.Value.ToString(); + + writer.WriteStringValue(stringValue); + } +} diff --git a/src/EntityDb.Redis/Converters/VersionNumberConverter.cs b/src/EntityDb.Json/Converters/VersionNumberConverter.cs similarity index 90% rename from src/EntityDb.Redis/Converters/VersionNumberConverter.cs rename to src/EntityDb.Json/Converters/VersionNumberConverter.cs index 8c9a127e..c4d097f9 100644 --- a/src/EntityDb.Redis/Converters/VersionNumberConverter.cs +++ b/src/EntityDb.Json/Converters/VersionNumberConverter.cs @@ -1,38 +1,37 @@ -using EntityDb.Abstractions.ValueObjects; -using System; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace EntityDb.Redis.Converters; - -internal class VersionNumberConverter : JsonConverter -{ - public override VersionNumber Read - ( - ref Utf8JsonReader reader, - Type typeToConvert, - JsonSerializerOptions options - ) - { - if (reader.TokenType != JsonTokenType.Number) - { - throw new NotSupportedException(); - } - - var ulongValue = reader.GetUInt64(); - - return new VersionNumber(ulongValue); - } - - public override void Write - ( - Utf8JsonWriter writer, - VersionNumber versionNumber, - JsonSerializerOptions options - ) - { - var ulongValue = versionNumber.Value; - - writer.WriteNumberValue(ulongValue); - } -} +using EntityDb.Abstractions.ValueObjects; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace EntityDb.Json.Converters; + +internal class VersionNumberConverter : JsonConverter +{ + public override VersionNumber Read + ( + ref Utf8JsonReader reader, + Type typeToConvert, + JsonSerializerOptions options + ) + { + if (reader.TokenType != JsonTokenType.Number) + { + throw new NotSupportedException(); + } + + var ulongValue = reader.GetUInt64(); + + return new VersionNumber(ulongValue); + } + + public override void Write + ( + Utf8JsonWriter writer, + VersionNumber versionNumber, + JsonSerializerOptions options + ) + { + var ulongValue = versionNumber.Value; + + writer.WriteNumberValue(ulongValue); + } +} diff --git a/src/EntityDb.Json/EntityDb.Json.csproj b/src/EntityDb.Json/EntityDb.Json.csproj new file mode 100644 index 00000000..7445c17f --- /dev/null +++ b/src/EntityDb.Json/EntityDb.Json.csproj @@ -0,0 +1,11 @@ + + + + false + + + + + + + diff --git a/src/EntityDb.Json/Envelopes/JsonBytesEnvelopeService.cs b/src/EntityDb.Json/Envelopes/JsonBytesEnvelopeService.cs new file mode 100644 index 00000000..e0a6dcc5 --- /dev/null +++ b/src/EntityDb.Json/Envelopes/JsonBytesEnvelopeService.cs @@ -0,0 +1,24 @@ +using EntityDb.Common.Envelopes; +using EntityDb.Common.TypeResolvers; +using Microsoft.Extensions.Logging; +using System.Text.Json; + +namespace EntityDb.Json.Envelopes; + +internal sealed class JsonBytesEnvelopeService : JsonEnvelopeService +{ + public JsonBytesEnvelopeService(ILogger logger, ITypeResolver typeResolver) : base(logger, typeResolver) + { + } + + protected override Envelope DeserializeEnvelope(byte[] serializedData) + { + return (Envelope)JsonSerializer.Deserialize(serializedData, typeof(Envelope), + JsonSerializerOptions)!; + } + + protected override byte[] SerializeEnvelope(Envelope envelope) + { + return JsonSerializer.SerializeToUtf8Bytes(envelope, typeof(Envelope), JsonSerializerOptions); + } +} diff --git a/src/EntityDb.Redis/Envelopes/JsonElementEnvelopeService.cs b/src/EntityDb.Json/Envelopes/JsonEnvelopeService.cs similarity index 50% rename from src/EntityDb.Redis/Envelopes/JsonElementEnvelopeService.cs rename to src/EntityDb.Json/Envelopes/JsonEnvelopeService.cs index 771224a7..f9a4a9e6 100644 --- a/src/EntityDb.Redis/Envelopes/JsonElementEnvelopeService.cs +++ b/src/EntityDb.Json/Envelopes/JsonEnvelopeService.cs @@ -1,104 +1,82 @@ -using EntityDb.Common.Envelopes; -using EntityDb.Common.Exceptions; -using EntityDb.Common.TypeResolvers; -using EntityDb.Redis.Converters; -using Microsoft.Extensions.Logging; -using System; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace EntityDb.Redis.Envelopes; - -internal sealed class JsonElementEnvelopeService : IEnvelopeService -{ - private static readonly JsonSerializerOptions JsonSerializerOptions = new() - { - DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull - }; - - private readonly ILogger _logger; - private readonly ITypeResolver _typeResolver; - - static JsonElementEnvelopeService() - { - JsonSerializerOptions.Converters.Add(new EnvelopeHeadersConverter()); - JsonSerializerOptions.Converters.Add(new IdConverter()); - JsonSerializerOptions.Converters.Add(new VersionNumberConverter()); - } - - public JsonElementEnvelopeService - ( - ILogger logger, - ITypeResolver typeResolver - ) - { - _logger = logger; - _typeResolver = typeResolver; - } - - public Envelope Deconstruct(TData data) - { - try - { - var dataType = data!.GetType(); - - var json = JsonSerializer.Serialize(data, dataType, JsonSerializerOptions); - - var jsonElement = JsonSerializer.Deserialize(json, JsonSerializerOptions); - - var headers = EnvelopeHelper.GetEnvelopeHeaders(dataType); - - return new Envelope(headers, jsonElement); - } - catch (Exception exception) - { - _logger.LogError(exception, "Unable to deconstruct"); - - throw new SerializeException(); - } - } - - public byte[] Serialize(Envelope envelope) - { - try - { - return JsonSerializer.SerializeToUtf8Bytes(envelope, typeof(Envelope), JsonSerializerOptions); - } - catch (Exception exception) - { - _logger.LogError(exception, "Unable to serialize"); - - throw new SerializeException(); - } - } - - public Envelope Deserialize(byte[] rawData) - { - try - { - return (Envelope)JsonSerializer.Deserialize(rawData, typeof(Envelope), - JsonSerializerOptions)!; - } - catch (Exception exception) - { - _logger.LogError(exception, "Unable to deserialize"); - - throw new DeserializeException(); - } - } - - public TData Reconstruct(Envelope envelope) - { - try - { - return (TData)JsonSerializer.Deserialize(envelope.Value.GetRawText(), - _typeResolver.ResolveType(envelope.Headers), JsonSerializerOptions)!; - } - catch (Exception exception) - { - _logger.LogError(exception, "Unable to reconstruct"); - - throw new DeserializeException(); - } - } -} +using EntityDb.Common.Envelopes; +using EntityDb.Common.Exceptions; +using EntityDb.Common.TypeResolvers; +using EntityDb.Json.Converters; +using Microsoft.Extensions.Logging; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace EntityDb.Json.Envelopes; + +internal abstract class JsonEnvelopeService : IEnvelopeService +{ + private readonly ILogger> _logger; + private readonly ITypeResolver _typeResolver; + + protected static readonly JsonSerializerOptions JsonSerializerOptions = new() + { + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull + }; + + static JsonEnvelopeService() + { + JsonSerializerOptions.Converters.Add(new EnvelopeHeadersConverter()); + JsonSerializerOptions.Converters.Add(new IdConverter()); + JsonSerializerOptions.Converters.Add(new VersionNumberConverter()); + } + + protected JsonEnvelopeService + ( + ILogger> logger, + ITypeResolver typeResolver + ) + { + _logger = logger; + _typeResolver = typeResolver; + } + + protected abstract TSerializedData SerializeEnvelope(Envelope envelope); + + protected abstract Envelope DeserializeEnvelope(TSerializedData serializedData); + + public TSerializedData Serialize(TData data) + { + try + { + var dataType = data!.GetType(); + + var json = JsonSerializer.Serialize(data, dataType, JsonSerializerOptions); + + var jsonElement = JsonSerializer.Deserialize(json, JsonSerializerOptions); + + var headers = EnvelopeHelper.GetEnvelopeHeaders(dataType); + + var envelope = new Envelope(headers, jsonElement); + + return SerializeEnvelope(envelope); + } + catch (Exception exception) + { + _logger.LogError(exception, "Unable to serialize"); + + throw new SerializeException(); + } + } + + public TData Deserialize(TSerializedData serializedData) + { + try + { + var envelope = DeserializeEnvelope(serializedData); + + return (TData)JsonSerializer.Deserialize(envelope.Value.GetRawText(), + _typeResolver.ResolveType(envelope.Headers), JsonSerializerOptions)!; + } + catch (Exception exception) + { + _logger.LogError(exception, "Unable to deserialize"); + + throw new DeserializeException(); + } + } +} diff --git a/src/EntityDb.Json/Envelopes/JsonStringEnvelopeService.cs b/src/EntityDb.Json/Envelopes/JsonStringEnvelopeService.cs new file mode 100644 index 00000000..55a37b5a --- /dev/null +++ b/src/EntityDb.Json/Envelopes/JsonStringEnvelopeService.cs @@ -0,0 +1,24 @@ +using EntityDb.Common.Envelopes; +using EntityDb.Common.TypeResolvers; +using Microsoft.Extensions.Logging; +using System.Text.Json; + +namespace EntityDb.Json.Envelopes; + +internal sealed class JsonStringEnvelopeService : JsonEnvelopeService +{ + public JsonStringEnvelopeService(ILogger logger, ITypeResolver typeResolver) : base(logger, typeResolver) + { + } + + protected override Envelope DeserializeEnvelope(string serializedData) + { + return (Envelope)JsonSerializer.Deserialize(serializedData, typeof(Envelope), + JsonSerializerOptions)!; + } + + protected override string SerializeEnvelope(Envelope envelope) + { + return JsonSerializer.Serialize(envelope, typeof(Envelope), JsonSerializerOptions); + } +} diff --git a/src/EntityDb.Json/Properties/AssemblyInfo.cs b/src/EntityDb.Json/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..19812737 --- /dev/null +++ b/src/EntityDb.Json/Properties/AssemblyInfo.cs @@ -0,0 +1,4 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("EntityDb.Npgsql")] +[assembly: InternalsVisibleTo("EntityDb.Redis")] diff --git a/src/EntityDb.Json/packages.lock.json b/src/EntityDb.Json/packages.lock.json new file mode 100644 index 00000000..030ca5af --- /dev/null +++ b/src/EntityDb.Json/packages.lock.json @@ -0,0 +1,34 @@ +{ + "version": 1, + "dependencies": { + "net6.0": { + "System.Linq.Async": { + "type": "Direct", + "requested": "[6.0.1, )", + "resolved": "6.0.1", + "contentHash": "0YhHcaroWpQ9UCot3Pizah7ryAzQhNvobLMSxeDIGmnXfkQn8u5owvpOH0K6EVB+z9L7u6Cc4W17Br/+jyttEQ==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "6.0.0" + } + }, + "Microsoft.Bcl.AsyncInterfaces": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==" + }, + "entitydb.abstractions": { + "type": "Project", + "dependencies": { + "System.Linq.Async": "6.0.1" + } + }, + "entitydb.common": { + "type": "Project", + "dependencies": { + "EntityDb.Abstractions": "1.0.0", + "System.Linq.Async": "6.0.1" + } + } + } + } +} \ No newline at end of file diff --git a/src/EntityDb.MongoDb.Provisioner/Commands/CommandBase.cs b/src/EntityDb.MongoDb.Provisioner/Commands/CommandBase.cs index 51fc96be..59bd2a82 100644 --- a/src/EntityDb.MongoDb.Provisioner/Commands/CommandBase.cs +++ b/src/EntityDb.MongoDb.Provisioner/Commands/CommandBase.cs @@ -1,7 +1,6 @@ using EntityDb.MongoDb.Provisioner.MongoDbAtlas; using System.CommandLine; using System.Text.RegularExpressions; -using System.Threading.Tasks; namespace EntityDb.MongoDb.Provisioner.Commands; diff --git a/src/EntityDb.MongoDb.Provisioner/Commands/CreateCollectionsCluster.cs b/src/EntityDb.MongoDb.Provisioner/Commands/CreateCollectionsCluster.cs index 4e695b27..48d41e3a 100644 --- a/src/EntityDb.MongoDb.Provisioner/Commands/CreateCollectionsCluster.cs +++ b/src/EntityDb.MongoDb.Provisioner/Commands/CreateCollectionsCluster.cs @@ -1,9 +1,7 @@ using EntityDb.MongoDb.Provisioner.Extensions; using MongoDB.Driver; -using System; using System.CommandLine; using System.CommandLine.NamingConventionBinder; -using System.Threading.Tasks; namespace EntityDb.MongoDb.Provisioner.Commands; diff --git a/src/EntityDb.MongoDb.Provisioner/Commands/CreateCollectionsDirect.cs b/src/EntityDb.MongoDb.Provisioner/Commands/CreateCollectionsDirect.cs index b03b6ae6..e80a0c0e 100644 --- a/src/EntityDb.MongoDb.Provisioner/Commands/CreateCollectionsDirect.cs +++ b/src/EntityDb.MongoDb.Provisioner/Commands/CreateCollectionsDirect.cs @@ -2,7 +2,6 @@ using MongoDB.Driver; using System.CommandLine; using System.CommandLine.NamingConventionBinder; -using System.Threading.Tasks; namespace EntityDb.MongoDb.Provisioner.Commands; diff --git a/src/EntityDb.MongoDb.Provisioner/Commands/CreateCollectionsServerless.cs b/src/EntityDb.MongoDb.Provisioner/Commands/CreateCollectionsServerless.cs index b0f98f5e..24e4fae3 100644 --- a/src/EntityDb.MongoDb.Provisioner/Commands/CreateCollectionsServerless.cs +++ b/src/EntityDb.MongoDb.Provisioner/Commands/CreateCollectionsServerless.cs @@ -1,9 +1,7 @@ using EntityDb.MongoDb.Provisioner.Extensions; using MongoDB.Driver; -using System; using System.CommandLine; using System.CommandLine.NamingConventionBinder; -using System.Threading.Tasks; namespace EntityDb.MongoDb.Provisioner.Commands; diff --git a/src/EntityDb.MongoDb.Provisioner/Commands/CreateRole.cs b/src/EntityDb.MongoDb.Provisioner/Commands/CreateRole.cs index 91011b5b..4b46e533 100644 --- a/src/EntityDb.MongoDb.Provisioner/Commands/CreateRole.cs +++ b/src/EntityDb.MongoDb.Provisioner/Commands/CreateRole.cs @@ -2,7 +2,6 @@ using EntityDb.MongoDb.Provisioner.MongoDbAtlas.Models; using System.CommandLine; using System.CommandLine.NamingConventionBinder; -using System.Threading.Tasks; namespace EntityDb.MongoDb.Provisioner.Commands; diff --git a/src/EntityDb.MongoDb.Provisioner/Commands/CreateUser.cs b/src/EntityDb.MongoDb.Provisioner/Commands/CreateUser.cs index 53c20e76..ebd4ed3e 100644 --- a/src/EntityDb.MongoDb.Provisioner/Commands/CreateUser.cs +++ b/src/EntityDb.MongoDb.Provisioner/Commands/CreateUser.cs @@ -1,7 +1,6 @@ using EntityDb.MongoDb.Provisioner.MongoDbAtlas.Models; using System.CommandLine; using System.CommandLine.NamingConventionBinder; -using System.Threading.Tasks; namespace EntityDb.MongoDb.Provisioner.Commands; diff --git a/src/EntityDb.MongoDb.Provisioner/EntityDb.MongoDb.Provisioner.csproj b/src/EntityDb.MongoDb.Provisioner/EntityDb.MongoDb.Provisioner.csproj index 2c8fe6b3..99e174fa 100644 --- a/src/EntityDb.MongoDb.Provisioner/EntityDb.MongoDb.Provisioner.csproj +++ b/src/EntityDb.MongoDb.Provisioner/EntityDb.MongoDb.Provisioner.csproj @@ -10,7 +10,7 @@ true entitydb-provision-mongodb EntityDb EventSourcing DDD CQRS MongoDb - A dotnet tool for provisioning a role, user, and database for usage with the EntityDb.MongoDb pacakge. Note - this tool is made for provisioning on a MongoDb Atlas Cluster. It does not work for other instances of MongoDb at this time. + A dotnet tool for provisioning a role, user, and database for usage with the EntityDb.MongoDb pacakge. diff --git a/src/EntityDb.MongoDb.Provisioner/Extensions/MongoClientExtensions.cs b/src/EntityDb.MongoDb.Provisioner/Extensions/MongoClientExtensions.cs index d9915087..feb8f793 100644 --- a/src/EntityDb.MongoDb.Provisioner/Extensions/MongoClientExtensions.cs +++ b/src/EntityDb.MongoDb.Provisioner/Extensions/MongoClientExtensions.cs @@ -1,9 +1,6 @@ using EntityDb.MongoDb.Documents; using MongoDB.Bson; using MongoDB.Driver; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.MongoDb.Provisioner.Extensions; diff --git a/src/EntityDb.MongoDb.Provisioner/Extensions/MongoDbTransactionRepositoryFactoryExtensions.cs b/src/EntityDb.MongoDb.Provisioner/Extensions/MongoDbTransactionRepositoryFactoryExtensions.cs index 78713483..0f4d2503 100644 --- a/src/EntityDb.MongoDb.Provisioner/Extensions/MongoDbTransactionRepositoryFactoryExtensions.cs +++ b/src/EntityDb.MongoDb.Provisioner/Extensions/MongoDbTransactionRepositoryFactoryExtensions.cs @@ -1,6 +1,5 @@ using EntityDb.MongoDb.Provisioner.Transactions; using EntityDb.MongoDb.Transactions; -using System; namespace EntityDb.MongoDb.Provisioner.Extensions; diff --git a/src/EntityDb.MongoDb.Provisioner/MongoDbAtlas/DigestChallengeRequest.cs b/src/EntityDb.MongoDb.Provisioner/MongoDbAtlas/DigestChallengeRequest.cs index c5248828..049d3469 100644 --- a/src/EntityDb.MongoDb.Provisioner/MongoDbAtlas/DigestChallengeRequest.cs +++ b/src/EntityDb.MongoDb.Provisioner/MongoDbAtlas/DigestChallengeRequest.cs @@ -1,6 +1,4 @@ -using System; -using System.Linq; -using System.Net.Http.Headers; +using System.Net.Http.Headers; using System.Security.Cryptography; using System.Text; using System.Text.Json; diff --git a/src/EntityDb.MongoDb.Provisioner/MongoDbAtlas/Models/ListOf.cs b/src/EntityDb.MongoDb.Provisioner/MongoDbAtlas/Models/ListOf.cs index cbcfafe6..3d3694c5 100644 --- a/src/EntityDb.MongoDb.Provisioner/MongoDbAtlas/Models/ListOf.cs +++ b/src/EntityDb.MongoDb.Provisioner/MongoDbAtlas/Models/ListOf.cs @@ -1,5 +1,4 @@ -using System; -using System.Text.Json.Serialization; +using System.Text.Json.Serialization; namespace EntityDb.MongoDb.Provisioner.MongoDbAtlas.Models; diff --git a/src/EntityDb.MongoDb.Provisioner/MongoDbAtlas/MongoDbAtlasClient.cs b/src/EntityDb.MongoDb.Provisioner/MongoDbAtlas/MongoDbAtlasClient.cs index 63198f45..f903ceda 100644 --- a/src/EntityDb.MongoDb.Provisioner/MongoDbAtlas/MongoDbAtlasClient.cs +++ b/src/EntityDb.MongoDb.Provisioner/MongoDbAtlas/MongoDbAtlasClient.cs @@ -1,12 +1,8 @@ using EntityDb.MongoDb.Provisioner.MongoDbAtlas.Models; -using System; -using System.Linq; using System.Net; -using System.Net.Http; using System.Net.Http.Headers; using System.Text; using System.Text.Json; -using System.Threading.Tasks; namespace EntityDb.MongoDb.Provisioner.MongoDbAtlas; diff --git a/src/EntityDb.MongoDb.Provisioner/Program.cs b/src/EntityDb.MongoDb.Provisioner/Program.cs index 14784929..2b73d9f8 100644 --- a/src/EntityDb.MongoDb.Provisioner/Program.cs +++ b/src/EntityDb.MongoDb.Provisioner/Program.cs @@ -1,7 +1,5 @@ using EntityDb.MongoDb.Provisioner.Commands; -using System; using System.CommandLine; -using System.Threading.Tasks; namespace EntityDb.MongoDb.Provisioner; diff --git a/src/EntityDb.MongoDb.Provisioner/Transactions/AutoProvisionMongoDbTransactionRepositoryFactory.cs b/src/EntityDb.MongoDb.Provisioner/Transactions/AutoProvisionMongoDbTransactionRepositoryFactory.cs index 397b047e..6dcac4ee 100644 --- a/src/EntityDb.MongoDb.Provisioner/Transactions/AutoProvisionMongoDbTransactionRepositoryFactory.cs +++ b/src/EntityDb.MongoDb.Provisioner/Transactions/AutoProvisionMongoDbTransactionRepositoryFactory.cs @@ -3,9 +3,6 @@ using EntityDb.MongoDb.Transactions; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using System; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.MongoDb.Provisioner.Transactions; diff --git a/src/EntityDb.MongoDb.Provisioner/packages.lock.json b/src/EntityDb.MongoDb.Provisioner/packages.lock.json index a0f858e1..e0c9db66 100644 --- a/src/EntityDb.MongoDb.Provisioner/packages.lock.json +++ b/src/EntityDb.MongoDb.Provisioner/packages.lock.json @@ -17,6 +17,15 @@ "System.CommandLine": "2.0.0-beta4.22272.1" } }, + "System.Linq.Async": { + "type": "Direct", + "requested": "[6.0.1, )", + "resolved": "6.0.1", + "contentHash": "0YhHcaroWpQ9UCot3Pizah7ryAzQhNvobLMSxeDIGmnXfkQn8u5owvpOH0K6EVB+z9L7u6Cc4W17Br/+jyttEQ==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "6.0.0" + } + }, "DnsClient": { "type": "Transitive", "resolved": "1.6.1", @@ -25,6 +34,11 @@ "Microsoft.Win32.Registry": "5.0.0" } }, + "Microsoft.Bcl.AsyncInterfaces": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==" + }, "Microsoft.NETCore.Platforms": { "type": "Transitive", "resolved": "5.0.0", @@ -41,38 +55,38 @@ }, "MongoDB.Bson": { "type": "Transitive", - "resolved": "2.16.1", - "contentHash": "d647KTPQ7hWqJmvCg80iiVdm239llaUwMyIeRF/0zKpN+ddRWh9jT/g6R6WQrmi4qd7yodvv/Jn0rpEqh4QN8g==", + "resolved": "2.17.1", + "contentHash": "IBr5w6ygeUCTobiS4J2UlYeIsnjSJvOOf31g60EkRa3NIeyrYs7Y51HeOvJ8r6NPcKv1hLj8xwoop6hDTetAdA==", "dependencies": { "System.Runtime.CompilerServices.Unsafe": "5.0.0" } }, "MongoDB.Driver": { "type": "Transitive", - "resolved": "2.16.1", - "contentHash": "LqDWfRG7gM1tZKcG9Q/vuQGYF5GsBuxUF5KcOgvWrE6P7pSkOSL9xGZ7ABZ6XRVECGEQs+N6GyU1E4ViI4lh+g==", + "resolved": "2.17.1", + "contentHash": "A5Yvm3RUdkSYnvKWVb/bZfvhzG+L+t0n80JuUXf0p2QG1TbtqHE9hX/FBK+BoF7sw9rzUTw8VHYeqX5rT0rxdA==", "dependencies": { - "MongoDB.Bson": "2.16.1", - "MongoDB.Driver.Core": "2.16.1", - "MongoDB.Libmongocrypt": "1.5.3" + "MongoDB.Bson": "2.17.1", + "MongoDB.Driver.Core": "2.17.1", + "MongoDB.Libmongocrypt": "1.5.5" } }, "MongoDB.Driver.Core": { "type": "Transitive", - "resolved": "2.16.1", - "contentHash": "oJZnXHnAyTd/haHYdbfKMRmPEZ1fFrndv8xhorHeTkUDeGgsPA89vpGMHcjppUyHMYBpLgHbn6GoMkleHKsTHg==", + "resolved": "2.17.1", + "contentHash": "lfuuQvCXcco6mG096PL8xRO+dBdHsDTR3DiYfK/ICHgFlL5RfKlBuE0xClEGKtaZ4Spe28/fF/GUcrrA/yfoAQ==", "dependencies": { "DnsClient": "1.6.1", - "MongoDB.Bson": "2.16.1", - "MongoDB.Libmongocrypt": "1.5.3", + "MongoDB.Bson": "2.17.1", + "MongoDB.Libmongocrypt": "1.5.5", "SharpCompress": "0.30.1", "System.Buffers": "4.5.1" } }, "MongoDB.Libmongocrypt": { "type": "Transitive", - "resolved": "1.5.3", - "contentHash": "OWWxuyuxbjAmOLPoaoUEYnIW4F7qexS6XYOdu6absxyGAqLBWEY+M4WY2Y0km2UUG1+QOPdebpb/7cg5BIEbdw==" + "resolved": "1.5.5", + "contentHash": "0DV4l2PjXirSJHD/b+LpOK3IfUDvkbpvvZBM2w1aYL6E/4vbhfyr/FP5laDNx2zRylqN1hIZO+EL7NgO/5GpVg==" }, "SharpCompress": { "type": "Transitive", @@ -104,19 +118,24 @@ "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==" }, "entitydb.abstractions": { - "type": "Project" + "type": "Project", + "dependencies": { + "System.Linq.Async": "6.0.1" + } }, "entitydb.common": { "type": "Project", "dependencies": { - "EntityDb.Abstractions": "1.0.0" + "EntityDb.Abstractions": "1.0.0", + "System.Linq.Async": "6.0.1" } }, "entitydb.mongodb": { "type": "Project", "dependencies": { "EntityDb.Common": "1.0.0", - "MongoDB.Driver": "2.16.1" + "MongoDB.Driver": "2.17.1", + "System.Linq.Async": "6.0.1" } } } diff --git a/src/EntityDb.MongoDb/Commands/DeleteDocumentsCommand.cs b/src/EntityDb.MongoDb/Commands/DeleteDocumentsCommand.cs index 2fd83491..0e9930fc 100644 --- a/src/EntityDb.MongoDb/Commands/DeleteDocumentsCommand.cs +++ b/src/EntityDb.MongoDb/Commands/DeleteDocumentsCommand.cs @@ -1,8 +1,6 @@ using EntityDb.MongoDb.Sessions; using MongoDB.Bson; using MongoDB.Driver; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.MongoDb.Commands; diff --git a/src/EntityDb.MongoDb/Commands/InsertDocumentsCommand.cs b/src/EntityDb.MongoDb/Commands/InsertDocumentsCommand.cs index 554d0003..7494c333 100644 --- a/src/EntityDb.MongoDb/Commands/InsertDocumentsCommand.cs +++ b/src/EntityDb.MongoDb/Commands/InsertDocumentsCommand.cs @@ -1,6 +1,4 @@ using EntityDb.MongoDb.Sessions; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.MongoDb.Commands; diff --git a/src/EntityDb.MongoDb/Documents/AgentSignatureDocument.cs b/src/EntityDb.MongoDb/Documents/AgentSignatureDocument.cs index a4bbbd75..811f79d3 100644 --- a/src/EntityDb.MongoDb/Documents/AgentSignatureDocument.cs +++ b/src/EntityDb.MongoDb/Documents/AgentSignatureDocument.cs @@ -7,7 +7,6 @@ using EntityDb.MongoDb.Queries.FilterBuilders; using EntityDb.MongoDb.Queries.SortBuilders; using MongoDB.Bson; -using System.Linq; namespace EntityDb.MongoDb.Documents; @@ -35,7 +34,8 @@ ITransaction transaction TransactionId = transaction.Id, EntityIds = transaction.Steps.Select(transactionStep => transactionStep.EntityId).Distinct() .ToArray(), - Data = envelopeService.Deconstruct(transaction.AgentSignature) + DataType = transaction.AgentSignature.GetType().Name, + Data = envelopeService.Serialize(transaction.AgentSignature) } }; @@ -57,7 +57,8 @@ IAgentSignatureQuery agentSignatureQuery agentSignatureQuery.GetFilter(FilterBuilder), agentSignatureQuery.GetSort(SortBuilder), agentSignatureQuery.Skip, - agentSignatureQuery.Take + agentSignatureQuery.Take, + agentSignatureQuery.Options as MongoDbQueryOptions ); } } diff --git a/src/EntityDb.MongoDb/Documents/CommandDocument.cs b/src/EntityDb.MongoDb/Documents/CommandDocument.cs index 05438d8f..2be01095 100644 --- a/src/EntityDb.MongoDb/Documents/CommandDocument.cs +++ b/src/EntityDb.MongoDb/Documents/CommandDocument.cs @@ -11,8 +11,6 @@ using EntityDb.MongoDb.Queries.SortBuilders; using EntityDb.MongoDb.Sessions; using MongoDB.Bson; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.MongoDb.Documents; @@ -42,7 +40,8 @@ IAppendCommandTransactionStep appendCommandTransactionStep TransactionId = transaction.Id, EntityId = appendCommandTransactionStep.EntityId, EntityVersionNumber = appendCommandTransactionStep.EntityVersionNumber, - Data = envelopeService.Deconstruct(appendCommandTransactionStep.Command) + DataType = appendCommandTransactionStep.Command.GetType().Name, + Data = envelopeService.Serialize(appendCommandTransactionStep.Command) } }; @@ -64,11 +63,12 @@ ICommandQuery commandQuery commandQuery.GetFilter(FilterBuilder), commandQuery.GetSort(SortBuilder), commandQuery.Skip, - commandQuery.Take + commandQuery.Take, + commandQuery.Options as MongoDbQueryOptions ); } - public static Task GetLastEntityVersionNumber + public static async Task GetLastEntityVersionNumber ( IMongoSession mongoSession, Id entityId, @@ -79,6 +79,12 @@ CancellationToken cancellationToken var documentQuery = GetQuery(commandQuery); - return documentQuery.GetEntityVersionNumber(mongoSession, cancellationToken); + var document = await documentQuery + .Execute(mongoSession, DocumentQueryExtensions.EntityVersionNumberProjection, cancellationToken) + .SingleOrDefaultAsync(cancellationToken); + + return document is null + ? default + : document.EntityVersionNumber; } } diff --git a/src/EntityDb.MongoDb/Documents/DocumentBase.cs b/src/EntityDb.MongoDb/Documents/DocumentBase.cs index 0097e377..506bdae3 100644 --- a/src/EntityDb.MongoDb/Documents/DocumentBase.cs +++ b/src/EntityDb.MongoDb/Documents/DocumentBase.cs @@ -1,15 +1,15 @@ using EntityDb.Abstractions.ValueObjects; -using EntityDb.Common.Envelopes; using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; namespace EntityDb.MongoDb.Documents; -internal abstract record DocumentBase : ITransactionDocument +internal abstract record DocumentBase { [BsonIgnoreIfNull] public ObjectId? _id { get; init; } public TimeStamp TransactionTimeStamp { get; init; } public Id TransactionId { get; init; } - public Envelope Data { get; init; } + public string DataType { get; init; } = default!; + public BsonDocument Data { get; init; } = default!; } diff --git a/src/EntityDb.MongoDb/Documents/IEntitiesDocument.cs b/src/EntityDb.MongoDb/Documents/IEntitiesDocument.cs index 472a86fb..eac8e58f 100644 --- a/src/EntityDb.MongoDb/Documents/IEntitiesDocument.cs +++ b/src/EntityDb.MongoDb/Documents/IEntitiesDocument.cs @@ -1,8 +1,8 @@ -using EntityDb.Abstractions.ValueObjects; +using EntityDb.Common.Documents; +using MongoDB.Bson; namespace EntityDb.MongoDb.Documents; -internal interface IEntitiesDocument : ITransactionDocument +internal interface IEntitiesDocument : IEntitiesDocument, ITransactionDocument { - Id[] EntityIds { get; } } diff --git a/src/EntityDb.MongoDb/Documents/IEntityDocument.cs b/src/EntityDb.MongoDb/Documents/IEntityDocument.cs index 5493b60d..bb15331e 100644 --- a/src/EntityDb.MongoDb/Documents/IEntityDocument.cs +++ b/src/EntityDb.MongoDb/Documents/IEntityDocument.cs @@ -1,9 +1,8 @@ -using EntityDb.Abstractions.ValueObjects; +using EntityDb.Common.Documents; +using MongoDB.Bson; namespace EntityDb.MongoDb.Documents; -internal interface IEntityDocument : ITransactionDocument +internal interface IEntityDocument : IEntityDocument, ITransactionDocument { - Id EntityId { get; } - VersionNumber EntityVersionNumber { get; } } diff --git a/src/EntityDb.MongoDb/Documents/ITransactionDocument.cs b/src/EntityDb.MongoDb/Documents/ITransactionDocument.cs index 121da2ec..cdc6d3b0 100644 --- a/src/EntityDb.MongoDb/Documents/ITransactionDocument.cs +++ b/src/EntityDb.MongoDb/Documents/ITransactionDocument.cs @@ -1,19 +1,12 @@ -using EntityDb.Abstractions.ValueObjects; -using EntityDb.Common.Envelopes; +using EntityDb.Common.Documents; using MongoDB.Bson; namespace EntityDb.MongoDb.Documents; -internal interface ITransactionDocument +internal interface ITransactionDocument : ITransactionDocument { #pragma warning disable IDE1006 // Naming Styles // ReSharper disable once InconsistentNaming ObjectId? _id { get; } #pragma warning restore IDE1006 // Naming Styles - - Id TransactionId { get; } - - TimeStamp TransactionTimeStamp { get; } - - Envelope Data { get; } } diff --git a/src/EntityDb.MongoDb/Documents/LeaseDocument.cs b/src/EntityDb.MongoDb/Documents/LeaseDocument.cs index 3b64b6e0..4b41c3ea 100644 --- a/src/EntityDb.MongoDb/Documents/LeaseDocument.cs +++ b/src/EntityDb.MongoDb/Documents/LeaseDocument.cs @@ -9,7 +9,6 @@ using EntityDb.MongoDb.Queries.FilterBuilders; using EntityDb.MongoDb.Queries.SortBuilders; using MongoDB.Bson; -using System.Linq; namespace EntityDb.MongoDb.Documents; @@ -43,10 +42,11 @@ IAddLeasesTransactionStep addLeasesTransactionStep TransactionId = transaction.Id, EntityId = addLeasesTransactionStep.EntityId, EntityVersionNumber = addLeasesTransactionStep.EntityVersionNumber, + DataType = insertLease.GetType().Name, + Data = envelopeService.Serialize(insertLease), Scope = insertLease.Scope, Label = insertLease.Label, - Value = insertLease.Value, - Data = envelopeService.Deconstruct(insertLease) + Value = insertLease.Value }) .ToArray(); @@ -68,7 +68,8 @@ ILeaseQuery leaseQuery leaseQuery.GetFilter(FilterBuilder), leaseQuery.GetSort(SortBuilder), leaseQuery.Skip, - leaseQuery.Take + leaseQuery.Take, + leaseQuery.Options as MongoDbQueryOptions ); } diff --git a/src/EntityDb.MongoDb/Documents/TagDocument.cs b/src/EntityDb.MongoDb/Documents/TagDocument.cs index faf5c8a3..82052aba 100644 --- a/src/EntityDb.MongoDb/Documents/TagDocument.cs +++ b/src/EntityDb.MongoDb/Documents/TagDocument.cs @@ -9,7 +9,6 @@ using EntityDb.MongoDb.Queries.FilterBuilders; using EntityDb.MongoDb.Queries.SortBuilders; using MongoDB.Bson; -using System.Linq; namespace EntityDb.MongoDb.Documents; @@ -42,9 +41,10 @@ IAddTagsTransactionStep addTagsTransactionStep TransactionId = transaction.Id, EntityId = addTagsTransactionStep.EntityId, EntityVersionNumber = addTagsTransactionStep.EntityVersionNumber, + DataType = insertTag.GetType().Name, + Data = envelopeService.Serialize(insertTag), Label = insertTag.Label, - Value = insertTag.Value, - Data = envelopeService.Deconstruct(insertTag) + Value = insertTag.Value }) .ToArray(); @@ -66,7 +66,8 @@ ITagQuery tagQuery tagQuery.GetFilter(FilterBuilder), tagQuery.GetSort(SortBuilder), tagQuery.Skip, - tagQuery.Take + tagQuery.Take, + tagQuery.Options as MongoDbQueryOptions ); } diff --git a/src/EntityDb.MongoDb/EntityDb.MongoDb.csproj b/src/EntityDb.MongoDb/EntityDb.MongoDb.csproj index df065304..9a59d756 100644 --- a/src/EntityDb.MongoDb/EntityDb.MongoDb.csproj +++ b/src/EntityDb.MongoDb/EntityDb.MongoDb.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/EntityDb.MongoDb/Envelopes/BsonDocumentEnvelopeService.cs b/src/EntityDb.MongoDb/Envelopes/BsonDocumentEnvelopeService.cs index c9c19b26..198f3a66 100644 --- a/src/EntityDb.MongoDb/Envelopes/BsonDocumentEnvelopeService.cs +++ b/src/EntityDb.MongoDb/Envelopes/BsonDocumentEnvelopeService.cs @@ -6,26 +6,25 @@ using Microsoft.Extensions.Logging; using MongoDB.Bson; using MongoDB.Bson.Serialization; -using System; namespace EntityDb.MongoDb.Envelopes; -internal class BsonDocumentEnvelopeService : IEnvelopeService +internal class MongoDbEnvelopeService : IEnvelopeService { public const string TypeDiscriminatorPropertyName = "_t"; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly bool _removeTypeDiscriminatorProperty; private readonly ITypeResolver _typeResolver; - static BsonDocumentEnvelopeService() + static MongoDbEnvelopeService() { BsonSerializer.RegisterSerializer(new EnvelopeSerializer()); } - public BsonDocumentEnvelopeService + public MongoDbEnvelopeService ( - ILogger logger, + ILogger logger, ITypeResolver typeResolver, bool removeTypeDiscriminatorProperty ) @@ -35,7 +34,7 @@ bool removeTypeDiscriminatorProperty _removeTypeDiscriminatorProperty = removeTypeDiscriminatorProperty; } - public Envelope Deconstruct(TData data) + public BsonDocument Serialize(TData data) { try { @@ -48,21 +47,9 @@ public Envelope Deconstruct(TData data) var headers = EnvelopeHelper.GetEnvelopeHeaders(data!.GetType()); - return new Envelope(headers, bsonDocument); - } - catch (Exception exception) - { - _logger.LogError(exception, "Unable to deconstruct"); - - throw new SerializeException(); - } - } + var envelope = new Envelope(headers, bsonDocument); - public byte[] Serialize(Envelope envelope) - { - try - { - return envelope.ToBsonDocument().ToBson(); + return envelope.ToBsonDocument(); } catch (Exception exception) { @@ -72,31 +59,17 @@ public byte[] Serialize(Envelope envelope) } } - public Envelope Deserialize(byte[] rawData) + public TData Deserialize(BsonDocument serializedData) { try { - var bsonDocument = new RawBsonDocument(rawData); + var envelope = (Envelope)BsonSerializer.Deserialize(serializedData, typeof(Envelope)); - return (Envelope)BsonSerializer.Deserialize(bsonDocument, typeof(Envelope)); - } - catch (Exception exception) - { - _logger.LogError(exception, "Unable to deserialize"); - - throw new DeserializeException(); - } - } - - public TData Reconstruct(Envelope envelope) - { - try - { return (TData)BsonSerializer.Deserialize(envelope.Value, _typeResolver.ResolveType(envelope.Headers)); } catch (Exception exception) { - _logger.LogError(exception, "Unable to reconstruct"); + _logger.LogError(exception, "Unable to deserialize"); throw new DeserializeException(); } @@ -105,7 +78,7 @@ public TData Reconstruct(Envelope envelope) public static IEnvelopeService Create(IServiceProvider serviceProvider, bool removeTypeDiscriminatorProperty) { - return ActivatorUtilities.CreateInstance(serviceProvider, + return ActivatorUtilities.CreateInstance(serviceProvider, removeTypeDiscriminatorProperty); } } diff --git a/src/EntityDb.MongoDb/Extensions/DocumentQueryExtensions.cs b/src/EntityDb.MongoDb/Extensions/DocumentQueryExtensions.cs index 24ccd64a..6e6d8c47 100644 --- a/src/EntityDb.MongoDb/Extensions/DocumentQueryExtensions.cs +++ b/src/EntityDb.MongoDb/Extensions/DocumentQueryExtensions.cs @@ -1,17 +1,14 @@ using EntityDb.Abstractions.Annotations; using EntityDb.Abstractions.ValueObjects; -using EntityDb.Common.Annotations; using EntityDb.Common.Envelopes; +using EntityDb.Common.Extensions; +using EntityDb.Common.Polyfills; using EntityDb.MongoDb.Documents; using EntityDb.MongoDb.Queries; using EntityDb.MongoDb.Sessions; using MongoDB.Bson; using MongoDB.Driver; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; +using System.Runtime.CompilerServices; namespace EntityDb.MongoDb.Extensions; @@ -39,36 +36,19 @@ internal static class DocumentQueryExtensions ProjectionBuilder.Include(nameof(ITransactionDocument.Data)) ); - private static readonly ProjectionDefinition EntityVersionNumberProjection = + public static readonly ProjectionDefinition EntityVersionNumberProjection = ProjectionBuilder.Combine ( ProjectionBuilder.Exclude(nameof(IEntityDocument._id)), ProjectionBuilder.Include(nameof(IEntityDocument.EntityVersionNumber)) ); - public static async Task GetEntityVersionNumber - ( - this DocumentQuery documentQuery, - IMongoSession mongoSession, - CancellationToken cancellationToken - ) - where TDocument : IEntityDocument - { - var documents = await documentQuery.Execute(mongoSession, EntityVersionNumberProjection, cancellationToken); - - var document = documents.SingleOrDefault(); - - return document is null - ? default - : document.EntityVersionNumber; - } - - private static async Task GetIds + private static IAsyncEnumerable EnumerateIds ( this DocumentQuery documentQuery, IMongoSession mongoSession, ProjectionDefinition projection, - Func, IEnumerable> mapToIds, + Func, IAsyncEnumerable> mapToIds, CancellationToken cancellationToken ) { @@ -77,89 +57,46 @@ CancellationToken cancellationToken documentQuery = documentQuery with { Skip = null, Limit = null }; - var documents = await documentQuery.Execute(mongoSession, projection, cancellationToken); - - var ids = mapToIds - .Invoke(documents) - .Distinct(); - - if (skip.HasValue) - { - ids = ids.Skip(skip.Value); - } - - if (limit.HasValue) - { - ids = ids.Take(limit.Value); - } + var documents = documentQuery.Execute(mongoSession, projection, cancellationToken); - return ids.ToArray(); + return documents.EnumerateIds(skip, limit, mapToIds); } - public static async Task[]> GetEntityAnnotation + public static IAsyncEnumerable EnumerateTransactionIds ( this DocumentQuery documentQuery, IMongoSession mongoSession, - IEnvelopeService envelopeService, CancellationToken cancellationToken ) - where TDocument : IEntityDocument - where TData : notnull + where TDocument : ITransactionDocument { - var documents = await documentQuery.Execute(mongoSession, NoDocumentIdProjection, cancellationToken); - - return documents - .Select(document => EntityAnnotation.CreateFromBoxedData - ( - document.TransactionId, - document.TransactionTimeStamp, - document.EntityId, - document.EntityVersionNumber, - envelopeService.Reconstruct(document.Data) - )) - .ToArray(); + return documentQuery.EnumerateIds + ( + mongoSession, + TransactionIdProjection, + documents => documents.Select(document => document.TransactionId), + cancellationToken + ); } - public static async Task[]> GetEntitiesAnnotation + public static IAsyncEnumerable EnumerateEntitiesIds ( this DocumentQuery documentQuery, IMongoSession mongoSession, - IEnvelopeService envelopeService, CancellationToken cancellationToken ) where TDocument : IEntitiesDocument - where TData : notnull - { - var documents = await documentQuery.Execute(mongoSession, NoDocumentIdProjection, cancellationToken); - - return documents - .Select(document => EntitiesAnnotation.CreateFromBoxedData - ( - document.TransactionId, - document.TransactionTimeStamp, - document.EntityIds, - envelopeService.Reconstruct(document.Data) - )) - .ToArray(); - } - - public static async Task GetData - ( - this DocumentQuery documentQuery, - IMongoSession mongoSession, - IEnvelopeService envelopeService, - CancellationToken cancellationToken - ) - where TDocument : ITransactionDocument { - var documents = await documentQuery.Execute(mongoSession, DataProjection, cancellationToken); - - return documents - .Select(document => envelopeService.Reconstruct(document.Data)) - .ToArray(); + return documentQuery.EnumerateIds + ( + mongoSession, + EntityIdsProjection, + documents => documents.SelectMany(document => AsyncEnumerablePolyfill.FromResult(document.EntityIds)), + cancellationToken + ); } - public static Task GetEntityIds + public static IAsyncEnumerable EnumerateEntityIds ( this DocumentQuery documentQuery, IMongoSession mongoSession, @@ -167,7 +104,7 @@ CancellationToken cancellationToken ) where TDocument : IEntityDocument { - return documentQuery.GetIds + return documentQuery.EnumerateIds ( mongoSession, EntityIdProjection, @@ -176,37 +113,50 @@ CancellationToken cancellationToken ); } - public static Task GetEntitiesIds + public static async IAsyncEnumerable EnumerateData + ( + this DocumentQuery documentQuery, + IMongoSession mongoSession, + IEnvelopeService envelopeService, + [EnumeratorCancellation] CancellationToken cancellationToken + ) + where TDocument : ITransactionDocument + { + var documents = documentQuery.Execute(mongoSession, DataProjection, cancellationToken); + + await foreach (var document in documents) + { + yield return envelopeService.Deserialize(document.Data); + } + } + + public static IAsyncEnumerable> EnumerateEntityAnnotation ( this DocumentQuery documentQuery, IMongoSession mongoSession, + IEnvelopeService envelopeService, CancellationToken cancellationToken ) - where TDocument : IEntitiesDocument + where TDocument : IEntityDocument + where TData : notnull { - return documentQuery.GetIds - ( - mongoSession, - EntityIdsProjection, - documents => documents.SelectMany(document => document.EntityIds), - cancellationToken - ); + var documents = documentQuery.Execute(mongoSession, NoDocumentIdProjection, cancellationToken); + + return documents.EnumerateEntityAnnotation(envelopeService, cancellationToken); } - public static Task GetTransactionIds + public static IAsyncEnumerable> EnumerateEntitiesAnnotation ( this DocumentQuery documentQuery, IMongoSession mongoSession, + IEnvelopeService envelopeService, CancellationToken cancellationToken ) - where TDocument : ITransactionDocument + where TDocument : IEntitiesDocument + where TData : notnull { - return documentQuery.GetIds - ( - mongoSession, - TransactionIdProjection, - documents => documents.Select(document => document.TransactionId), - cancellationToken - ); + var documents = documentQuery.Execute(mongoSession, NoDocumentIdProjection, cancellationToken); + + return documents.EnumerateEntitiesAnnotation(envelopeService, cancellationToken); } } diff --git a/src/EntityDb.MongoDb/Extensions/ServiceCollectionExtensions.cs b/src/EntityDb.MongoDb/Extensions/ServiceCollectionExtensions.cs index 20a95913..bf3e3cc5 100644 --- a/src/EntityDb.MongoDb/Extensions/ServiceCollectionExtensions.cs +++ b/src/EntityDb.MongoDb/Extensions/ServiceCollectionExtensions.cs @@ -18,7 +18,7 @@ internal static void AddBsonDocumentEnvelopeService(this IServiceCollection serv bool removeTypeDiscriminatorProperty) { serviceCollection.AddSingleton(serviceProvider => - BsonDocumentEnvelopeService.Create(serviceProvider, removeTypeDiscriminatorProperty)); + MongoDbEnvelopeService.Create(serviceProvider, removeTypeDiscriminatorProperty)); } /// diff --git a/src/EntityDb.MongoDb/Queries/BuilderBase.cs b/src/EntityDb.MongoDb/Queries/BuilderBase.cs index bf873bf2..ab134302 100644 --- a/src/EntityDb.MongoDb/Queries/BuilderBase.cs +++ b/src/EntityDb.MongoDb/Queries/BuilderBase.cs @@ -1,13 +1,14 @@ using EntityDb.Common.Envelopes; using EntityDb.MongoDb.Documents; +using MongoDB.Bson; namespace EntityDb.MongoDb.Queries; internal abstract class BuilderBase { protected const string DataTypeNameFieldName = - $"{nameof(DocumentBase.Data)}.{nameof(DocumentBase.Data.Headers)}.{EnvelopeHelper.Type}"; + $"{nameof(DocumentBase.Data)}.{nameof(Envelope.Headers)}.{EnvelopeHelper.Type}"; protected const string DataValueFieldName = - $"{nameof(DocumentBase.Data)}.{nameof(DocumentBase.Data.Value)}"; + $"{nameof(DocumentBase.Data)}.{nameof(Envelope.Value)}"; } diff --git a/src/EntityDb.MongoDb/Queries/DocumentQuery.cs b/src/EntityDb.MongoDb/Queries/DocumentQuery.cs index 9c0f1d9a..c1f76a19 100644 --- a/src/EntityDb.MongoDb/Queries/DocumentQuery.cs +++ b/src/EntityDb.MongoDb/Queries/DocumentQuery.cs @@ -1,9 +1,6 @@ using EntityDb.MongoDb.Sessions; using MongoDB.Bson; using MongoDB.Driver; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.MongoDb.Queries; @@ -13,12 +10,12 @@ internal record DocumentQuery FilterDefinition Filter, SortDefinition? Sort, int? Skip, - int? Limit + int? Limit, + MongoDbQueryOptions? Options ) { - public Task> Execute(IMongoSession mongoSession, - ProjectionDefinition projection, CancellationToken cancellationToken) + public IAsyncEnumerable Execute(IMongoSession mongoSession, ProjectionDefinition projection, CancellationToken cancellationToken) { - return mongoSession.Find(CollectionName, Filter, projection, Sort, Skip, Limit, cancellationToken); + return mongoSession.Find(CollectionName, Filter, projection, Sort, Skip, Limit, Options, cancellationToken); } } diff --git a/src/EntityDb.MongoDb/Queries/FilterBuilders/AgentSignatureFilterBuilder.cs b/src/EntityDb.MongoDb/Queries/FilterBuilders/AgentSignatureFilterBuilder.cs index 35826cc8..9d0a68ae 100644 --- a/src/EntityDb.MongoDb/Queries/FilterBuilders/AgentSignatureFilterBuilder.cs +++ b/src/EntityDb.MongoDb/Queries/FilterBuilders/AgentSignatureFilterBuilder.cs @@ -3,7 +3,7 @@ using EntityDb.MongoDb.Documents; using MongoDB.Bson; using MongoDB.Driver; -using System; +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; namespace EntityDb.MongoDb.Queries.FilterBuilders; @@ -21,6 +21,8 @@ public FilterDefinition AgentSignatureTypeIn(params Type[] agentSi return DataTypeIn(agentSignatureTypes); } + [Obsolete("This method will be removed in the future, and may not be supported for all implementations.")] + [ExcludeFromCodeCoverage(Justification = "Obsolete")] public FilterDefinition AgentSignatureMatches( Expression> agentSignatureExpression) { diff --git a/src/EntityDb.MongoDb/Queries/FilterBuilders/CommandFilterBuilder.cs b/src/EntityDb.MongoDb/Queries/FilterBuilders/CommandFilterBuilder.cs index 6753e14d..8972e58a 100644 --- a/src/EntityDb.MongoDb/Queries/FilterBuilders/CommandFilterBuilder.cs +++ b/src/EntityDb.MongoDb/Queries/FilterBuilders/CommandFilterBuilder.cs @@ -3,7 +3,7 @@ using EntityDb.MongoDb.Documents; using MongoDB.Bson; using MongoDB.Driver; -using System; +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; namespace EntityDb.MongoDb.Queries.FilterBuilders; @@ -31,6 +31,8 @@ public FilterDefinition CommandTypeIn(params Type[] commandTypes) return DataTypeIn(commandTypes); } + [Obsolete("This method will be removed in the future, and may not be supported for all implementations.")] + [ExcludeFromCodeCoverage(Justification = "Obsolete")] public FilterDefinition CommandMatches( Expression> commandExpression) { diff --git a/src/EntityDb.MongoDb/Queries/FilterBuilders/FilterBuilderBase.cs b/src/EntityDb.MongoDb/Queries/FilterBuilders/FilterBuilderBase.cs index 2a354514..9d663b9d 100644 --- a/src/EntityDb.MongoDb/Queries/FilterBuilders/FilterBuilderBase.cs +++ b/src/EntityDb.MongoDb/Queries/FilterBuilders/FilterBuilderBase.cs @@ -5,8 +5,7 @@ using EntityDb.MongoDb.Queries.FilterDefinitions; using MongoDB.Bson; using MongoDB.Driver; -using System; -using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; namespace EntityDb.MongoDb.Queries.FilterBuilders; @@ -45,6 +44,11 @@ public FilterDefinition Or(params FilterDefinition[] return FilterBuilder.Or(filters); } + protected static FilterDefinition Eq(string fieldName, TValue value) + { + return FilterBuilder.Eq(fieldName, value); + } + protected static FilterDefinition In(string fieldName, IEnumerable values) { return FilterBuilder.In(fieldName, values); @@ -77,6 +81,8 @@ protected virtual string[] GetHoistedFieldNames() return Array.Empty(); } + [Obsolete("This method will be removed in the future, and may not be supported for all implementations.")] + [ExcludeFromCodeCoverage(Justification = "Obsolete")] protected FilterDefinition DataValueMatches(Expression> dataExpression) { var dataFilter = Builders.Filter.Where(dataExpression); diff --git a/src/EntityDb.MongoDb/Queries/FilterBuilders/LeaseFilterBuilder.cs b/src/EntityDb.MongoDb/Queries/FilterBuilders/LeaseFilterBuilder.cs index eb611f21..d5db785d 100644 --- a/src/EntityDb.MongoDb/Queries/FilterBuilders/LeaseFilterBuilder.cs +++ b/src/EntityDb.MongoDb/Queries/FilterBuilders/LeaseFilterBuilder.cs @@ -3,7 +3,7 @@ using EntityDb.MongoDb.Documents; using MongoDB.Bson; using MongoDB.Driver; -using System; +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; namespace EntityDb.MongoDb.Queries.FilterBuilders; @@ -30,6 +30,23 @@ public FilterDefinition LeaseTypeIn(params Type[] leaseTypes) return DataTypeIn(leaseTypes); } + public FilterDefinition LeaseScopeEq(string scope) + { + return Eq(nameof(LeaseDocument.Scope), scope); + } + + public FilterDefinition LeaseLabelEq(string label) + { + return Eq(nameof(LeaseDocument.Label), label); + } + + public FilterDefinition LeaseValueEq(string value) + { + return Eq(nameof(LeaseDocument.Value), value); + } + + [Obsolete("This method will be removed in the future, and may not be supported for all implementations.")] + [ExcludeFromCodeCoverage(Justification = "Obsolete")] public FilterDefinition LeaseMatches(Expression> leaseExpression) { return DataValueMatches(leaseExpression); diff --git a/src/EntityDb.MongoDb/Queries/FilterBuilders/TagFilterBuilder.cs b/src/EntityDb.MongoDb/Queries/FilterBuilders/TagFilterBuilder.cs index ba96f996..4d27c204 100644 --- a/src/EntityDb.MongoDb/Queries/FilterBuilders/TagFilterBuilder.cs +++ b/src/EntityDb.MongoDb/Queries/FilterBuilders/TagFilterBuilder.cs @@ -3,7 +3,7 @@ using EntityDb.MongoDb.Documents; using MongoDB.Bson; using MongoDB.Driver; -using System; +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; namespace EntityDb.MongoDb.Queries.FilterBuilders; @@ -30,6 +30,18 @@ public FilterDefinition TagTypeIn(params Type[] tagTypes) return DataTypeIn(tagTypes); } + public FilterDefinition TagLabelEq(string label) + { + return Eq(nameof(TagDocument.Label), label); + } + + public FilterDefinition TagValueEq(string value) + { + return Eq(nameof(TagDocument.Value), value); + } + + [Obsolete("This method will be removed in the future, and may not be supported for all implementations.")] + [ExcludeFromCodeCoverage(Justification = "Obsolete")] public FilterDefinition TagMatches(Expression> tagExpression) { return DataValueMatches(tagExpression); diff --git a/src/EntityDb.MongoDb/Queries/MongoDbQueryOptions.cs b/src/EntityDb.MongoDb/Queries/MongoDbQueryOptions.cs new file mode 100644 index 00000000..d7ad85dd --- /dev/null +++ b/src/EntityDb.MongoDb/Queries/MongoDbQueryOptions.cs @@ -0,0 +1,14 @@ +using MongoDB.Driver; + +namespace EntityDb.MongoDb.Queries; + +/// +/// Options for configuring queries in MongoDb. +/// +public class MongoDbQueryOptions +{ + /// + /// Options for finding documents. + /// + public FindOptions? FindOptions { get; set; } +} diff --git a/src/EntityDb.MongoDb/Queries/SortBuilders/AgentSignatureSortBuilder.cs b/src/EntityDb.MongoDb/Queries/SortBuilders/AgentSignatureSortBuilder.cs index 9c975afa..7a85b8df 100644 --- a/src/EntityDb.MongoDb/Queries/SortBuilders/AgentSignatureSortBuilder.cs +++ b/src/EntityDb.MongoDb/Queries/SortBuilders/AgentSignatureSortBuilder.cs @@ -2,7 +2,6 @@ using EntityDb.MongoDb.Documents; using MongoDB.Bson; using MongoDB.Driver; -using System; using System.Linq.Expressions; namespace EntityDb.MongoDb.Queries.SortBuilders; diff --git a/src/EntityDb.MongoDb/Queries/SortBuilders/CommandSortBuilder.cs b/src/EntityDb.MongoDb/Queries/SortBuilders/CommandSortBuilder.cs index 1e2f3ead..8f16ed01 100644 --- a/src/EntityDb.MongoDb/Queries/SortBuilders/CommandSortBuilder.cs +++ b/src/EntityDb.MongoDb/Queries/SortBuilders/CommandSortBuilder.cs @@ -2,7 +2,6 @@ using EntityDb.MongoDb.Documents; using MongoDB.Bson; using MongoDB.Driver; -using System; using System.Linq.Expressions; namespace EntityDb.MongoDb.Queries.SortBuilders; diff --git a/src/EntityDb.MongoDb/Queries/SortBuilders/LeaseSortBuilder.cs b/src/EntityDb.MongoDb/Queries/SortBuilders/LeaseSortBuilder.cs index f677a3e0..342185c0 100644 --- a/src/EntityDb.MongoDb/Queries/SortBuilders/LeaseSortBuilder.cs +++ b/src/EntityDb.MongoDb/Queries/SortBuilders/LeaseSortBuilder.cs @@ -2,7 +2,6 @@ using EntityDb.MongoDb.Documents; using MongoDB.Bson; using MongoDB.Driver; -using System; using System.Linq.Expressions; namespace EntityDb.MongoDb.Queries.SortBuilders; @@ -30,6 +29,21 @@ public SortDefinition LeaseProperty(bool ascending, return SortDataValue(ascending, leaseExpression); } + public SortDefinition LeaseScope(bool ascending) + { + return Sort(ascending, nameof(LeaseDocument.Scope)); + } + + public SortDefinition LeaseLabel(bool ascending) + { + return Sort(ascending, nameof(LeaseDocument.Label)); + } + + public SortDefinition LeaseValue(bool ascending) + { + return Sort(ascending, nameof(LeaseDocument.Value)); + } + protected override string[] GetHoistedFieldNames() { return LeaseDocument.HoistedFieldNames; diff --git a/src/EntityDb.MongoDb/Queries/SortBuilders/SortBuilderBase.cs b/src/EntityDb.MongoDb/Queries/SortBuilders/SortBuilderBase.cs index a51ae692..503ab422 100644 --- a/src/EntityDb.MongoDb/Queries/SortBuilders/SortBuilderBase.cs +++ b/src/EntityDb.MongoDb/Queries/SortBuilders/SortBuilderBase.cs @@ -3,7 +3,6 @@ using EntityDb.MongoDb.Queries.SortDefinitions; using MongoDB.Bson; using MongoDB.Driver; -using System; using System.Linq.Expressions; namespace EntityDb.MongoDb.Queries.SortBuilders; diff --git a/src/EntityDb.MongoDb/Queries/SortBuilders/TagSortBuilder.cs b/src/EntityDb.MongoDb/Queries/SortBuilders/TagSortBuilder.cs index 3e48eedc..9f80c7fe 100644 --- a/src/EntityDb.MongoDb/Queries/SortBuilders/TagSortBuilder.cs +++ b/src/EntityDb.MongoDb/Queries/SortBuilders/TagSortBuilder.cs @@ -2,7 +2,6 @@ using EntityDb.MongoDb.Documents; using MongoDB.Bson; using MongoDB.Driver; -using System; using System.Linq.Expressions; namespace EntityDb.MongoDb.Queries.SortBuilders; @@ -30,6 +29,16 @@ public SortDefinition TagProperty(bool ascending, return SortDataValue(ascending, leaseExpression); } + public SortDefinition TagLabel(bool ascending) + { + return Sort(ascending, nameof(TagDocument.Label)); + } + + public SortDefinition TagValue(bool ascending) + { + return Sort(ascending, nameof(TagDocument.Value)); + } + protected override string[] GetHoistedFieldNames() { return TagDocument.HoistedFieldNames; diff --git a/src/EntityDb.MongoDb/Rewriters/BsonDocumentRewriter.cs b/src/EntityDb.MongoDb/Rewriters/BsonDocumentRewriter.cs index 34e7763f..93375aa6 100644 --- a/src/EntityDb.MongoDb/Rewriters/BsonDocumentRewriter.cs +++ b/src/EntityDb.MongoDb/Rewriters/BsonDocumentRewriter.cs @@ -1,8 +1,5 @@ using MongoDB.Bson; using MongoDB.Bson.IO; -using System; -using System.Collections.Generic; -using System.Linq; namespace EntityDb.MongoDb.Rewriters; diff --git a/src/EntityDb.MongoDb/Rewriters/HoistedRewriter.cs b/src/EntityDb.MongoDb/Rewriters/HoistedRewriter.cs index af9ce9cd..0fe95422 100644 --- a/src/EntityDb.MongoDb/Rewriters/HoistedRewriter.cs +++ b/src/EntityDb.MongoDb/Rewriters/HoistedRewriter.cs @@ -1,7 +1,5 @@ using MongoDB.Bson; using MongoDB.Bson.IO; -using System.Collections.Generic; -using System.Linq; namespace EntityDb.MongoDb.Rewriters; diff --git a/src/EntityDb.MongoDb/Serializers/EnvelopeSerializer.cs b/src/EntityDb.MongoDb/Serializers/EnvelopeSerializer.cs index 2306f4e2..95a9104a 100644 --- a/src/EntityDb.MongoDb/Serializers/EnvelopeSerializer.cs +++ b/src/EntityDb.MongoDb/Serializers/EnvelopeSerializer.cs @@ -3,8 +3,6 @@ using MongoDB.Bson.IO; using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; -using System; -using System.Collections.Generic; namespace EntityDb.MongoDb.Serializers; diff --git a/src/EntityDb.MongoDb/Serializers/IdSerializer.cs b/src/EntityDb.MongoDb/Serializers/IdSerializer.cs index 2325bace..fb029335 100644 --- a/src/EntityDb.MongoDb/Serializers/IdSerializer.cs +++ b/src/EntityDb.MongoDb/Serializers/IdSerializer.cs @@ -1,6 +1,5 @@ using EntityDb.Abstractions.ValueObjects; using MongoDB.Bson.Serialization; -using System; namespace EntityDb.MongoDb.Serializers; diff --git a/src/EntityDb.MongoDb/Serializers/TimeStampSerializer.cs b/src/EntityDb.MongoDb/Serializers/TimeStampSerializer.cs index cddd7f41..def754e2 100644 --- a/src/EntityDb.MongoDb/Serializers/TimeStampSerializer.cs +++ b/src/EntityDb.MongoDb/Serializers/TimeStampSerializer.cs @@ -1,6 +1,5 @@ using EntityDb.Abstractions.ValueObjects; using MongoDB.Bson.Serialization; -using System; namespace EntityDb.MongoDb.Serializers; diff --git a/src/EntityDb.MongoDb/Serializers/VersionNumberSerializer.cs b/src/EntityDb.MongoDb/Serializers/VersionNumberSerializer.cs index 220e0628..a3c635cc 100644 --- a/src/EntityDb.MongoDb/Serializers/VersionNumberSerializer.cs +++ b/src/EntityDb.MongoDb/Serializers/VersionNumberSerializer.cs @@ -1,6 +1,5 @@ using EntityDb.Abstractions.ValueObjects; using MongoDB.Bson.Serialization; -using System; namespace EntityDb.MongoDb.Serializers; diff --git a/src/EntityDb.MongoDb/Sessions/IMongoSession.cs b/src/EntityDb.MongoDb/Sessions/IMongoSession.cs index 5da8bb58..aed64aa4 100644 --- a/src/EntityDb.MongoDb/Sessions/IMongoSession.cs +++ b/src/EntityDb.MongoDb/Sessions/IMongoSession.cs @@ -1,9 +1,7 @@ using EntityDb.Abstractions.Disposables; +using EntityDb.MongoDb.Queries; using MongoDB.Bson; using MongoDB.Driver; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.MongoDb.Sessions; @@ -14,7 +12,7 @@ internal interface IMongoSession : IDisposableResource Task Insert(string collectionName, TDocument[] bsonDocuments, CancellationToken cancellationToken); - Task> Find + IAsyncEnumerable Find ( string collectionName, FilterDefinition filterDefinition, @@ -22,6 +20,7 @@ Task> Find SortDefinition? sortDefinition, int? skip, int? limit, + MongoDbQueryOptions? options, CancellationToken cancellationToken ); diff --git a/src/EntityDb.MongoDb/Sessions/MongoDbTransactionSessionOptions.cs b/src/EntityDb.MongoDb/Sessions/MongoDbTransactionSessionOptions.cs index 2ce219d9..44d7789f 100644 --- a/src/EntityDb.MongoDb/Sessions/MongoDbTransactionSessionOptions.cs +++ b/src/EntityDb.MongoDb/Sessions/MongoDbTransactionSessionOptions.cs @@ -1,6 +1,5 @@ using EntityDb.Abstractions.Transactions; using MongoDB.Driver; -using System; namespace EntityDb.MongoDb.Sessions; @@ -34,11 +33,6 @@ public class MongoDbTransactionSessionOptions /// public TimeSpan? WriteTimeout { get; set; } - /// - /// Determines how long to wait before a query should be automatically killed. - /// - public TimeSpan? ReadTimeout { get; set; } - /// public override string ToString() { diff --git a/src/EntityDb.MongoDb/Sessions/MongoSession.cs b/src/EntityDb.MongoDb/Sessions/MongoSession.cs index 0ee371e7..83ec7ad2 100644 --- a/src/EntityDb.MongoDb/Sessions/MongoSession.cs +++ b/src/EntityDb.MongoDb/Sessions/MongoSession.cs @@ -1,14 +1,12 @@ using EntityDb.Common.Disposables; using EntityDb.Common.Exceptions; +using EntityDb.MongoDb.Queries; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using MongoDB.Bson; using MongoDB.Driver; -using System; -using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.Threading; -using System.Threading.Tasks; +using System.Runtime.CompilerServices; namespace EntityDb.MongoDb.Sessions; @@ -59,7 +57,7 @@ await MongoDatabase ); } - public async Task> Find + public async IAsyncEnumerable Find ( string collectionName, FilterDefinition filter, @@ -67,14 +65,15 @@ public async Task> Find SortDefinition? sort, int? skip, int? limit, - CancellationToken cancellationToken + MongoDbQueryOptions? options, + [EnumeratorCancellation] CancellationToken cancellationToken ) { var find = MongoDatabase .GetCollection(collectionName) .WithReadPreference(GetReadPreference()) .WithReadConcern(GetReadConcern()) - .Find(ClientSessionHandle, filter, new FindOptions { MaxTime = Options.ReadTimeout }) + .Find(ClientSessionHandle, filter, options?.FindOptions) .Project(projection); if (sort is not null) @@ -98,29 +97,41 @@ CancellationToken cancellationToken Logger .LogInformation ( - "Started Running MongoDb Query on `{DatabaseNamespace}.{CollectionName}`\n\nServer Session Id: {ServerSessionId}\n\nQuery: {Query}", + "Started Enumerating MongoDb Query on `{DatabaseNamespace}.{CollectionName}`\n\nServer Session Id: {ServerSessionId}\n\nQuery: {Query}", MongoDatabase.DatabaseNamespace, collectionName, serverSessionId, query ); - var documents = await find.ToListAsync(cancellationToken); + ulong documentCount = 0; + + using var cursor = await find.ToCursorAsync(cancellationToken); + + while (await cursor.MoveNextAsync(cancellationToken)) + { + foreach (var document in cursor.Current) + { + documentCount += 1; + + yield return document; + } + } Logger .LogInformation ( - "Finished Running MongoDb Query on `{DatabaseNamespace}.{CollectionName}`\n\nServer Session Id: {ServerSessionId}\n\nQuery: {Query}\n\nDocuments Returned: {DocumentsReturned}", + "Finished Enumerating MongoDb Query on `{DatabaseNamespace}.{CollectionName}`\n\nServer Session Id: {ServerSessionId}\n\nQuery: {Query}\n\nDocuments Returned: {DocumentsReturned}", MongoDatabase.DatabaseNamespace, collectionName, serverSessionId, query, - documents.Count + documentCount ); - - return documents; } + + public async Task Delete(string collectionName, FilterDefinition filterDefinition, CancellationToken cancellationToken) { @@ -197,7 +208,7 @@ public override ValueTask DisposeAsync() { ClientSessionHandle.Dispose(); - return ValueTask.CompletedTask; + return base.DisposeAsync(); } private ReadPreference GetReadPreference() diff --git a/src/EntityDb.MongoDb/Sessions/TestModeMongoSession.cs b/src/EntityDb.MongoDb/Sessions/TestModeMongoSession.cs index 0387010e..62269fe5 100644 --- a/src/EntityDb.MongoDb/Sessions/TestModeMongoSession.cs +++ b/src/EntityDb.MongoDb/Sessions/TestModeMongoSession.cs @@ -1,9 +1,7 @@ using EntityDb.Common.Disposables; +using EntityDb.MongoDb.Queries; using MongoDB.Bson; using MongoDB.Driver; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.MongoDb.Sessions; @@ -16,7 +14,7 @@ public Task Insert(string collectionName, TDocument[] bsonDocuments, return MongoSession.Insert(collectionName, bsonDocuments, cancellationToken); } - public Task> Find + public IAsyncEnumerable Find ( string collectionName, FilterDefinition filterDefinition, @@ -24,6 +22,7 @@ public Task> Find SortDefinition? sortDefinition, int? skip, int? limit, + MongoDbQueryOptions? options, CancellationToken cancellationToken ) { @@ -35,6 +34,7 @@ CancellationToken cancellationToken sortDefinition, skip, limit, + options, cancellationToken ); } diff --git a/src/EntityDb.MongoDb/Transactions/IMongoDbTransactionRepositoryFactory.cs b/src/EntityDb.MongoDb/Transactions/IMongoDbTransactionRepositoryFactory.cs index a908019c..a1664268 100644 --- a/src/EntityDb.MongoDb/Transactions/IMongoDbTransactionRepositoryFactory.cs +++ b/src/EntityDb.MongoDb/Transactions/IMongoDbTransactionRepositoryFactory.cs @@ -1,7 +1,5 @@ using EntityDb.Abstractions.Transactions; using EntityDb.MongoDb.Sessions; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.MongoDb.Transactions; diff --git a/src/EntityDb.MongoDb/Transactions/MongoDbTransactionRepository.cs b/src/EntityDb.MongoDb/Transactions/MongoDbTransactionRepository.cs index 4c9f7c2b..7f84b54b 100644 --- a/src/EntityDb.MongoDb/Transactions/MongoDbTransactionRepository.cs +++ b/src/EntityDb.MongoDb/Transactions/MongoDbTransactionRepository.cs @@ -12,9 +12,6 @@ using EntityDb.MongoDb.Extensions; using EntityDb.MongoDb.Sessions; using MongoDB.Bson; -using System; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.MongoDb.Transactions; @@ -33,107 +30,116 @@ IEnvelopeService envelopeService _envelopeService = envelopeService; } - public Task GetTransactionIds(IAgentSignatureQuery agentSignatureQuery, + public IAsyncEnumerable EnumerateTransactionIds(IAgentSignatureQuery agentSignatureQuery, CancellationToken cancellationToken = default) { return AgentSignatureDocument .GetQuery(agentSignatureQuery) - .GetTransactionIds(_mongoSession, cancellationToken); + .EnumerateTransactionIds(_mongoSession, cancellationToken); } - public Task GetTransactionIds(ICommandQuery commandQuery, CancellationToken cancellationToken = default) + public IAsyncEnumerable EnumerateTransactionIds(ICommandQuery commandQuery, + CancellationToken cancellationToken = default) { return CommandDocument .GetQuery(commandQuery) - .GetTransactionIds(_mongoSession, cancellationToken); + .EnumerateTransactionIds(_mongoSession, cancellationToken); } - public Task GetTransactionIds(ILeaseQuery leaseQuery, CancellationToken cancellationToken = default) + public IAsyncEnumerable EnumerateTransactionIds(ILeaseQuery leaseQuery, + CancellationToken cancellationToken = default) { return LeaseDocument .GetQuery(leaseQuery) - .GetTransactionIds(_mongoSession, cancellationToken); + .EnumerateTransactionIds(_mongoSession, cancellationToken); } - public Task GetTransactionIds(ITagQuery tagQuery, CancellationToken cancellationToken = default) + public IAsyncEnumerable EnumerateTransactionIds(ITagQuery tagQuery, + CancellationToken cancellationToken = default) { return TagDocument .GetQuery(tagQuery) - .GetTransactionIds(_mongoSession, cancellationToken); + .EnumerateTransactionIds(_mongoSession, cancellationToken); } - public Task GetEntityIds(IAgentSignatureQuery agentSignatureQuery, + public IAsyncEnumerable EnumerateEntityIds(IAgentSignatureQuery agentSignatureQuery, CancellationToken cancellationToken = default) { return AgentSignatureDocument .GetQuery(agentSignatureQuery) - .GetEntitiesIds(_mongoSession, cancellationToken); + .EnumerateEntitiesIds(_mongoSession, cancellationToken); } - public Task GetEntityIds(ICommandQuery commandQuery, CancellationToken cancellationToken = default) + public IAsyncEnumerable EnumerateEntityIds(ICommandQuery commandQuery, + CancellationToken cancellationToken = default) { return CommandDocument .GetQuery(commandQuery) - .GetEntityIds(_mongoSession, cancellationToken); + .EnumerateEntityIds(_mongoSession, cancellationToken); } - public Task GetEntityIds(ILeaseQuery leaseQuery, CancellationToken cancellationToken = default) + public IAsyncEnumerable EnumerateEntityIds(ILeaseQuery leaseQuery, + CancellationToken cancellationToken = default) { return LeaseDocument .GetQuery(leaseQuery) - .GetEntityIds(_mongoSession, cancellationToken); + .EnumerateEntityIds(_mongoSession, cancellationToken); } - public Task GetEntityIds(ITagQuery tagQuery, CancellationToken cancellationToken = default) + public IAsyncEnumerable EnumerateEntityIds(ITagQuery tagQuery, + CancellationToken cancellationToken = default) { return TagDocument .GetQuery(tagQuery) - .GetEntityIds(_mongoSession, cancellationToken); + .EnumerateEntityIds(_mongoSession, cancellationToken); } - public Task GetAgentSignatures(IAgentSignatureQuery agentSignatureQuery, + public IAsyncEnumerable EnumerateAgentSignatures(IAgentSignatureQuery agentSignatureQuery, CancellationToken cancellationToken = default) { return AgentSignatureDocument .GetQuery(agentSignatureQuery) - .GetData(_mongoSession, _envelopeService, cancellationToken); + .EnumerateData(_mongoSession, _envelopeService, cancellationToken); } - public Task GetCommands(ICommandQuery commandQuery, CancellationToken cancellationToken = default) + public IAsyncEnumerable EnumerateCommands(ICommandQuery commandQuery, + CancellationToken cancellationToken = default) { return CommandDocument .GetQuery(commandQuery) - .GetData(_mongoSession, _envelopeService, cancellationToken); + .EnumerateData(_mongoSession, _envelopeService, cancellationToken); } - public Task GetLeases(ILeaseQuery leaseQuery, CancellationToken cancellationToken = default) + public IAsyncEnumerable EnumerateLeases(ILeaseQuery leaseQuery, + CancellationToken cancellationToken = default) { return LeaseDocument .GetQuery(leaseQuery) - .GetData(_mongoSession, _envelopeService, cancellationToken); + .EnumerateData(_mongoSession, _envelopeService, cancellationToken); } - public Task GetTags(ITagQuery tagQuery, CancellationToken cancellationToken = default) + public IAsyncEnumerable EnumerateTags(ITagQuery tagQuery, + CancellationToken cancellationToken = default) { return TagDocument .GetQuery(tagQuery) - .GetData(_mongoSession, _envelopeService, cancellationToken); + .EnumerateData(_mongoSession, _envelopeService, cancellationToken); } - public Task[]> GetAnnotatedAgentSignatures(IAgentSignatureQuery agentSignatureQuery, + public IAsyncEnumerable> EnumerateAnnotatedAgentSignatures(IAgentSignatureQuery agentSignatureQuery, CancellationToken cancellationToken = default) { return AgentSignatureDocument .GetQuery(agentSignatureQuery) - .GetEntitiesAnnotation(_mongoSession, _envelopeService, cancellationToken); + .EnumerateEntitiesAnnotation(_mongoSession, _envelopeService, cancellationToken); } - public Task[]> GetAnnotatedCommands(ICommandQuery commandQuery, + public IAsyncEnumerable> EnumerateAnnotatedCommands(ICommandQuery commandQuery, CancellationToken cancellationToken = default) { return CommandDocument .GetQuery(commandQuery) - .GetEntityAnnotation(_mongoSession, _envelopeService, cancellationToken); + .EnumerateEntityAnnotation(_mongoSession, _envelopeService, cancellationToken); } public async Task PutTransaction(ITransaction transaction, CancellationToken cancellationToken = default) diff --git a/src/EntityDb.MongoDb/Transactions/MongoDbTransactionRepositoryFactory.cs b/src/EntityDb.MongoDb/Transactions/MongoDbTransactionRepositoryFactory.cs index 0e876286..99579cbe 100644 --- a/src/EntityDb.MongoDb/Transactions/MongoDbTransactionRepositoryFactory.cs +++ b/src/EntityDb.MongoDb/Transactions/MongoDbTransactionRepositoryFactory.cs @@ -8,9 +8,6 @@ using MongoDB.Bson; using MongoDB.Bson.Serialization; using MongoDB.Driver; -using System; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.MongoDb.Transactions; diff --git a/src/EntityDb.MongoDb/Transactions/MongoDbTransactionRepositoryFactoryWrapper.cs b/src/EntityDb.MongoDb/Transactions/MongoDbTransactionRepositoryFactoryWrapper.cs index 517e2679..d09474c8 100644 --- a/src/EntityDb.MongoDb/Transactions/MongoDbTransactionRepositoryFactoryWrapper.cs +++ b/src/EntityDb.MongoDb/Transactions/MongoDbTransactionRepositoryFactoryWrapper.cs @@ -1,8 +1,6 @@ using EntityDb.Abstractions.Transactions; using EntityDb.Common.Disposables; using EntityDb.MongoDb.Sessions; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.MongoDb.Transactions; diff --git a/src/EntityDb.MongoDb/Transactions/TestModeMongoDbTransactionRepositoryFactory.cs b/src/EntityDb.MongoDb/Transactions/TestModeMongoDbTransactionRepositoryFactory.cs index c42c6768..feaf17a9 100644 --- a/src/EntityDb.MongoDb/Transactions/TestModeMongoDbTransactionRepositoryFactory.cs +++ b/src/EntityDb.MongoDb/Transactions/TestModeMongoDbTransactionRepositoryFactory.cs @@ -1,6 +1,4 @@ using EntityDb.MongoDb.Sessions; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.MongoDb.Transactions; diff --git a/src/EntityDb.MongoDb/packages.lock.json b/src/EntityDb.MongoDb/packages.lock.json index 437d789c..bcba4d89 100644 --- a/src/EntityDb.MongoDb/packages.lock.json +++ b/src/EntityDb.MongoDb/packages.lock.json @@ -4,13 +4,22 @@ "net6.0": { "MongoDB.Driver": { "type": "Direct", - "requested": "[2.16.1, )", - "resolved": "2.16.1", - "contentHash": "LqDWfRG7gM1tZKcG9Q/vuQGYF5GsBuxUF5KcOgvWrE6P7pSkOSL9xGZ7ABZ6XRVECGEQs+N6GyU1E4ViI4lh+g==", + "requested": "[2.17.1, )", + "resolved": "2.17.1", + "contentHash": "A5Yvm3RUdkSYnvKWVb/bZfvhzG+L+t0n80JuUXf0p2QG1TbtqHE9hX/FBK+BoF7sw9rzUTw8VHYeqX5rT0rxdA==", "dependencies": { - "MongoDB.Bson": "2.16.1", - "MongoDB.Driver.Core": "2.16.1", - "MongoDB.Libmongocrypt": "1.5.3" + "MongoDB.Bson": "2.17.1", + "MongoDB.Driver.Core": "2.17.1", + "MongoDB.Libmongocrypt": "1.5.5" + } + }, + "System.Linq.Async": { + "type": "Direct", + "requested": "[6.0.1, )", + "resolved": "6.0.1", + "contentHash": "0YhHcaroWpQ9UCot3Pizah7ryAzQhNvobLMSxeDIGmnXfkQn8u5owvpOH0K6EVB+z9L7u6Cc4W17Br/+jyttEQ==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "6.0.0" } }, "DnsClient": { @@ -21,6 +30,11 @@ "Microsoft.Win32.Registry": "5.0.0" } }, + "Microsoft.Bcl.AsyncInterfaces": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==" + }, "Microsoft.NETCore.Platforms": { "type": "Transitive", "resolved": "5.0.0", @@ -37,28 +51,28 @@ }, "MongoDB.Bson": { "type": "Transitive", - "resolved": "2.16.1", - "contentHash": "d647KTPQ7hWqJmvCg80iiVdm239llaUwMyIeRF/0zKpN+ddRWh9jT/g6R6WQrmi4qd7yodvv/Jn0rpEqh4QN8g==", + "resolved": "2.17.1", + "contentHash": "IBr5w6ygeUCTobiS4J2UlYeIsnjSJvOOf31g60EkRa3NIeyrYs7Y51HeOvJ8r6NPcKv1hLj8xwoop6hDTetAdA==", "dependencies": { "System.Runtime.CompilerServices.Unsafe": "5.0.0" } }, "MongoDB.Driver.Core": { "type": "Transitive", - "resolved": "2.16.1", - "contentHash": "oJZnXHnAyTd/haHYdbfKMRmPEZ1fFrndv8xhorHeTkUDeGgsPA89vpGMHcjppUyHMYBpLgHbn6GoMkleHKsTHg==", + "resolved": "2.17.1", + "contentHash": "lfuuQvCXcco6mG096PL8xRO+dBdHsDTR3DiYfK/ICHgFlL5RfKlBuE0xClEGKtaZ4Spe28/fF/GUcrrA/yfoAQ==", "dependencies": { "DnsClient": "1.6.1", - "MongoDB.Bson": "2.16.1", - "MongoDB.Libmongocrypt": "1.5.3", + "MongoDB.Bson": "2.17.1", + "MongoDB.Libmongocrypt": "1.5.5", "SharpCompress": "0.30.1", "System.Buffers": "4.5.1" } }, "MongoDB.Libmongocrypt": { "type": "Transitive", - "resolved": "1.5.3", - "contentHash": "OWWxuyuxbjAmOLPoaoUEYnIW4F7qexS6XYOdu6absxyGAqLBWEY+M4WY2Y0km2UUG1+QOPdebpb/7cg5BIEbdw==" + "resolved": "1.5.5", + "contentHash": "0DV4l2PjXirSJHD/b+LpOK3IfUDvkbpvvZBM2w1aYL6E/4vbhfyr/FP5laDNx2zRylqN1hIZO+EL7NgO/5GpVg==" }, "SharpCompress": { "type": "Transitive", @@ -90,12 +104,16 @@ "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==" }, "entitydb.abstractions": { - "type": "Project" + "type": "Project", + "dependencies": { + "System.Linq.Async": "6.0.1" + } }, "entitydb.common": { "type": "Project", "dependencies": { - "EntityDb.Abstractions": "1.0.0" + "EntityDb.Abstractions": "1.0.0", + "System.Linq.Async": "6.0.1" } } } diff --git a/src/EntityDb.Mvc/Agents/HttpContextAgentAccessor.cs b/src/EntityDb.Mvc/Agents/HttpContextAgentAccessor.cs index 0f47db4c..77adf804 100644 --- a/src/EntityDb.Mvc/Agents/HttpContextAgentAccessor.cs +++ b/src/EntityDb.Mvc/Agents/HttpContextAgentAccessor.cs @@ -3,9 +3,6 @@ using EntityDb.Common.Exceptions; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Options; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.Mvc.Agents; diff --git a/src/EntityDb.Mvc/Agents/HttpContextAgentSignature.cs b/src/EntityDb.Mvc/Agents/HttpContextAgentSignature.cs index b47af7da..bfd864fb 100644 --- a/src/EntityDb.Mvc/Agents/HttpContextAgentSignature.cs +++ b/src/EntityDb.Mvc/Agents/HttpContextAgentSignature.cs @@ -1,7 +1,5 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; -using System.Collections.Generic; -using System.Linq; namespace EntityDb.Mvc.Agents; diff --git a/src/EntityDb.Mvc/Agents/HttpContextAgentSignatureOptions.cs b/src/EntityDb.Mvc/Agents/HttpContextAgentSignatureOptions.cs index 3dc03129..174d1e69 100644 --- a/src/EntityDb.Mvc/Agents/HttpContextAgentSignatureOptions.cs +++ b/src/EntityDb.Mvc/Agents/HttpContextAgentSignatureOptions.cs @@ -1,6 +1,4 @@ -using System; - -namespace EntityDb.Mvc.Agents; +namespace EntityDb.Mvc.Agents; /// /// Configuration options for the Http Context agent. diff --git a/src/EntityDb.Mvc/packages.lock.json b/src/EntityDb.Mvc/packages.lock.json index 8c9a5d5c..030ca5af 100644 --- a/src/EntityDb.Mvc/packages.lock.json +++ b/src/EntityDb.Mvc/packages.lock.json @@ -2,13 +2,31 @@ "version": 1, "dependencies": { "net6.0": { + "System.Linq.Async": { + "type": "Direct", + "requested": "[6.0.1, )", + "resolved": "6.0.1", + "contentHash": "0YhHcaroWpQ9UCot3Pizah7ryAzQhNvobLMSxeDIGmnXfkQn8u5owvpOH0K6EVB+z9L7u6Cc4W17Br/+jyttEQ==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "6.0.0" + } + }, + "Microsoft.Bcl.AsyncInterfaces": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==" + }, "entitydb.abstractions": { - "type": "Project" + "type": "Project", + "dependencies": { + "System.Linq.Async": "6.0.1" + } }, "entitydb.common": { "type": "Project", "dependencies": { - "EntityDb.Abstractions": "1.0.0" + "EntityDb.Abstractions": "1.0.0", + "System.Linq.Async": "6.0.1" } } } diff --git a/src/EntityDb.Npgsql.Provisioner/Commands/CommandBase.cs b/src/EntityDb.Npgsql.Provisioner/Commands/CommandBase.cs new file mode 100644 index 00000000..3a485e7c --- /dev/null +++ b/src/EntityDb.Npgsql.Provisioner/Commands/CommandBase.cs @@ -0,0 +1,49 @@ +using System.CommandLine; +using System.Text.RegularExpressions; + +namespace EntityDb.Npgsql.Provisioner.Commands; + +internal abstract class CommandBase +{ + private static readonly Regex ServiceNameRegex = new("^[a-z][a-z]*$", RegexOptions.IgnoreCase); + + protected static void AddConnectionStringArgument(Command command) + { + var connectionString = new Argument("connection-string") + { + Description = "The connection string for the database." + }; + + command.AddArgument(connectionString); + } + + protected static void AddServiceNameArgument(Command command) + { + var serviceName = new Argument("service-name") + { + Description = "The name of the service that will use this database." + }; + + serviceName.AddValidator(serviceNameResult => + { + var serviceName = serviceNameResult.GetValueOrDefault() ?? string.Empty; + + if (!ServiceNameRegex.IsMatch(serviceName)) + { + serviceNameResult.ErrorMessage = "The service name must begin with an letter, and can only contain letters."; + } + }); + + command.AddArgument(serviceName); + } + + protected static void AddServicePasswordArgument(Command command) + { + var servicePassword = new Argument("service-password") + { + Description = "The password for the service that will use this database." + }; + + command.AddArgument(servicePassword); + } +} diff --git a/src/EntityDb.Npgsql.Provisioner/Commands/CreateDatabase.cs b/src/EntityDb.Npgsql.Provisioner/Commands/CreateDatabase.cs new file mode 100644 index 00000000..137bc85c --- /dev/null +++ b/src/EntityDb.Npgsql.Provisioner/Commands/CreateDatabase.cs @@ -0,0 +1,38 @@ +using Npgsql; +using System.CommandLine; +using System.CommandLine.NamingConventionBinder; + +namespace EntityDb.Npgsql.Provisioner.Commands; + +internal class CreateDatabase : CommandBase +{ + public record Arguments + ( + string ConnectionString, + string ServiceName + ); + + private static async Task Execute(Arguments arguments) + { + var npgsqlConnection = new NpgsqlConnection(arguments.ConnectionString); + + await npgsqlConnection.OpenAsync(); + + await new NpgsqlCommand($"CREATE DATABASE {arguments.ServiceName} IF NOT EXISTS", npgsqlConnection).ExecuteNonQueryAsync(); + + await npgsqlConnection.CloseAsync(); + } + + public static void AddTo(RootCommand rootCommand) + { + var createCollectionsDirect = new Command("create-database") + { + Handler = CommandHandler.Create(Execute) + }; + + AddConnectionStringArgument(createCollectionsDirect); + AddServiceNameArgument(createCollectionsDirect); + + rootCommand.AddCommand(createCollectionsDirect); + } +} diff --git a/src/EntityDb.Npgsql.Provisioner/Commands/CreateRole.cs b/src/EntityDb.Npgsql.Provisioner/Commands/CreateRole.cs new file mode 100644 index 00000000..0c79a5f7 --- /dev/null +++ b/src/EntityDb.Npgsql.Provisioner/Commands/CreateRole.cs @@ -0,0 +1,53 @@ +using Npgsql; +using System.CommandLine; +using System.CommandLine.NamingConventionBinder; + +namespace EntityDb.Npgsql.Provisioner.Commands; + +internal class CreateRole : CommandBase +{ + public record Arguments + ( + string ConnectionString, + string ServiceName, + string ServicePassword + ); + + private static async Task Execute(Arguments arguments) + { + var npgsqlConnection = new NpgsqlConnection(arguments.ConnectionString); + + await npgsqlConnection.OpenAsync(); + + await npgsqlConnection.ChangeDatabaseAsync(arguments.ServiceName.ToLowerInvariant()); + + var commands = new[] + { + $"DROP ROLE IF EXISTS {arguments.ServiceName}", + $"CREATE USER {arguments.ServiceName} PASSWORD '{arguments.ServicePassword}'", + $"GRANT SELECT, INSERT ON TABLE agentsignatures, commands, leases, tags TO {arguments.ServiceName}", + $"GRANT DELETE ON TABLE leases, tags TO {arguments.ServiceName}" + }; + + foreach (var command in commands) + { + await new NpgsqlCommand(command, npgsqlConnection).ExecuteNonQueryAsync(); + } + + await npgsqlConnection.CloseAsync(); + } + + public static void AddTo(RootCommand rootCommand) + { + var createRole = new Command("create-role") + { + Handler = CommandHandler.Create(Execute) + }; + + AddConnectionStringArgument(createRole); + AddServiceNameArgument(createRole); + AddServicePasswordArgument(createRole); + + rootCommand.AddCommand(createRole); + } +} diff --git a/src/EntityDb.Npgsql.Provisioner/Commands/CreateTables.cs b/src/EntityDb.Npgsql.Provisioner/Commands/CreateTables.cs new file mode 100644 index 00000000..1661861a --- /dev/null +++ b/src/EntityDb.Npgsql.Provisioner/Commands/CreateTables.cs @@ -0,0 +1,42 @@ +using EntityDb.Npgsql.Provisioner.Extensions; +using Npgsql; +using System.CommandLine; +using System.CommandLine.NamingConventionBinder; + +namespace EntityDb.Npgsql.Provisioner.Commands; + +internal class CreateTables : CommandBase +{ + public record Arguments + ( + string ConnectionString, + string ServiceName, + string ServicePassword + ); + + private static async Task Execute(Arguments arguments) + { + var npgsqlConnection = new NpgsqlConnection(arguments.ConnectionString); + + await npgsqlConnection.OpenAsync(); + + await npgsqlConnection.ChangeDatabaseAsync(arguments.ServiceName.ToLowerInvariant()); + + await npgsqlConnection.ProvisionTables(); + + await npgsqlConnection.CloseAsync(); + } + + public static void AddTo(RootCommand rootCommand) + { + var createRole = new Command("create-tables") + { + Handler = CommandHandler.Create(Execute) + }; + + AddConnectionStringArgument(createRole); + AddServiceNameArgument(createRole); + + rootCommand.AddCommand(createRole); + } +} diff --git a/src/EntityDb.Npgsql.Provisioner/EntityDb.Npgsql.Provisioner.csproj b/src/EntityDb.Npgsql.Provisioner/EntityDb.Npgsql.Provisioner.csproj new file mode 100644 index 00000000..7cbfc6a2 --- /dev/null +++ b/src/EntityDb.Npgsql.Provisioner/EntityDb.Npgsql.Provisioner.csproj @@ -0,0 +1,25 @@ + + + + + Exe + + + + + true + entitydb-provision-npgsql + EntityDb EventSourcing DDD CQRS Npgsql Postgres + A dotnet tool for provisioning a role, user, and database for usage with the EntityDb.Npgsql pacakge. + + + + + + + + + + + + diff --git a/src/EntityDb.Npgsql.Provisioner/Extensions/NpgsqlConnectionExtensions.cs b/src/EntityDb.Npgsql.Provisioner/Extensions/NpgsqlConnectionExtensions.cs new file mode 100644 index 00000000..7ac99936 --- /dev/null +++ b/src/EntityDb.Npgsql.Provisioner/Extensions/NpgsqlConnectionExtensions.cs @@ -0,0 +1,93 @@ +using EntityDb.SqlDb.Documents.AgentSignature; +using EntityDb.SqlDb.Documents.Command; +using EntityDb.SqlDb.Documents.Lease; +using EntityDb.SqlDb.Documents.Tag; +using Npgsql; + +namespace EntityDb.Npgsql.Provisioner.Extensions; + +/// +/// Extensions for the Npgsql Connection. +/// +public static class NpgsqlConnectionExtensions +{ + private static readonly string[] Commands = + { + "CREATE COLLATION IF NOT EXISTS numeric (provider = icu, locale = 'en-u-kn-true');", + + "CREATE extension IF NOT EXISTS \"uuid-ossp\"", + + $"CREATE TABLE IF NOT EXISTS AgentSignatures (" + + $"{nameof(AgentSignatureDocument.Id)} uuid DEFAULT uuid_generate_v4() PRIMARY KEY, " + + $"{nameof(AgentSignatureDocument.TransactionId)} uuid NOT NULL, " + + $"{nameof(AgentSignatureDocument.TransactionTimeStamp)} timestamp with time zone NOT NULL, " + + $"{nameof(AgentSignatureDocument.EntityIds)} uuid[] NOT NULL, " + + $"{nameof(AgentSignatureDocument.DataType)} varchar NOT NULL, " + + $"{nameof(AgentSignatureDocument.Data)} jsonb NOT NULL " + + $")", + + $"CREATE UNIQUE INDEX IF NOT EXISTS UniqueAgentSignatures ON AgentSignatures ({nameof(AgentSignatureDocument.TransactionId)})", + + $"CREATE TABLE IF NOT EXISTS Commands (" + + $"{nameof(CommandDocument.Id)} uuid DEFAULT uuid_generate_v4() PRIMARY KEY, " + + $"{nameof(CommandDocument.TransactionId)} uuid NOT NULL, " + + $"{nameof(CommandDocument.TransactionTimeStamp)} timestamp with time zone NOT NULL, " + + $"{nameof(CommandDocument.EntityId)} uuid NOT NULL, " + + $"{nameof(CommandDocument.EntityVersionNumber)} bigint NOT NULL, " + + $"{nameof(CommandDocument.DataType)} varchar NOT NULL, " + + $"{nameof(CommandDocument.Data)} jsonb NOT NULL " + + $")", + + $"CREATE UNIQUE INDEX IF NOT EXISTS UniqueCommands ON Commands ({nameof(CommandDocument.EntityId)}, {nameof(CommandDocument.EntityVersionNumber)})", + + $"CREATE TABLE IF NOT EXISTS Leases (" + + $"{nameof(LeaseDocument.Id)} uuid DEFAULT uuid_generate_v4() PRIMARY KEY, " + + $"{nameof(LeaseDocument.TransactionId)} uuid NOT NULL, " + + $"{nameof(LeaseDocument.TransactionTimeStamp)} timestamp with time zone NOT NULL, " + + $"{nameof(LeaseDocument.EntityId)} uuid NOT NULL, " + + $"{nameof(LeaseDocument.EntityVersionNumber)} bigint NOT NULL, " + + $"{nameof(LeaseDocument.DataType)} varchar NOT NULL, " + + $"{nameof(LeaseDocument.Data)} jsonb NOT NULL, " + + $"{nameof(LeaseDocument.Scope)} varchar NOT NULL, " + + $"{nameof(LeaseDocument.Label)} varchar NOT NULL, " + + $"{nameof(LeaseDocument.Value)} varchar NOT NULL " + + $")", + + $"CREATE UNIQUE INDEX IF NOT EXISTS UniqueLeases ON Leases ({nameof(LeaseDocument.Scope)}, {nameof(LeaseDocument.Label)}, {nameof(LeaseDocument.Value)})", + + $"CREATE TABLE IF NOT EXISTS Tags (" + + $"{nameof(TagDocument.Id)} uuid DEFAULT uuid_generate_v4() PRIMARY KEY, " + + $"{nameof(TagDocument.TransactionId)} uuid NOT NULL, " + + $"{nameof(TagDocument.TransactionTimeStamp)} timestamp with time zone NOT NULL, " + + $"{nameof(TagDocument.EntityId)} uuid NOT NULL, " + + $"{nameof(TagDocument.EntityVersionNumber)} bigint NOT NULL, " + + $"{nameof(TagDocument.DataType)} varchar NOT NULL, " + + $"{nameof(TagDocument.Data)} jsonb NOT NULL, " + + $"{nameof(TagDocument.Label)} varchar NOT NULL, " + + $"{nameof(TagDocument.Value)} varchar NOT NULL " + + $")", + + $"CREATE INDEX IF NOT EXISTS TagLookup ON Tags ({nameof(TagDocument.Label)}, {nameof(TagDocument.Value)})", + }; + + /// + /// Provisions the needed collections on the database. + /// + /// The npgsql connection. + /// A cancellation token. + /// An asynchronous task that, when complete, signals that the tables have been provisioned. + /// + /// You should ONLY use this in your code for integration testing. Real databases should be provisioned using the + /// dotnet tool EntityDb.Npgsql.Provisioner + /// + public static async Task ProvisionTables(this NpgsqlConnection npgsqlConnection, + CancellationToken cancellationToken = default) + { + foreach (var command in Commands) + { + var dbCommand = new NpgsqlCommand(command, npgsqlConnection); + + await dbCommand.ExecuteNonQueryAsync(cancellationToken); + } + } +} diff --git a/src/EntityDb.Npgsql.Provisioner/Extensions/NpgsqlTransactionRepositoryFactoryExtensions.cs b/src/EntityDb.Npgsql.Provisioner/Extensions/NpgsqlTransactionRepositoryFactoryExtensions.cs new file mode 100644 index 00000000..e459055a --- /dev/null +++ b/src/EntityDb.Npgsql.Provisioner/Extensions/NpgsqlTransactionRepositoryFactoryExtensions.cs @@ -0,0 +1,16 @@ +using EntityDb.Npgsql.Provisioner.Transactions; +using EntityDb.Npgsql.Queries; +using EntityDb.SqlDb.Transactions; + +namespace EntityDb.Npgsql.Provisioner.Extensions; + +internal static class NpgsqlTransactionRepositoryFactoryExtensions +{ + public static ISqlDbTransactionRepositoryFactory UseAutoProvisioning( + this ISqlDbTransactionRepositoryFactory npgsqlTransactionRepositoryFactory, + IServiceProvider serviceProvider) + { + return AutoProvisionNpgsqlTransactionRepositoryFactory.Create(serviceProvider, + npgsqlTransactionRepositoryFactory); + } +} diff --git a/src/EntityDb.Npgsql.Provisioner/Extensions/ServiceCollectionExtensions.cs b/src/EntityDb.Npgsql.Provisioner/Extensions/ServiceCollectionExtensions.cs new file mode 100644 index 00000000..608e8378 --- /dev/null +++ b/src/EntityDb.Npgsql.Provisioner/Extensions/ServiceCollectionExtensions.cs @@ -0,0 +1,40 @@ +using EntityDb.Abstractions.Transactions; +using EntityDb.Common.Extensions; +using EntityDb.Npgsql.Converters; +using EntityDb.Npgsql.Extensions; +using EntityDb.Npgsql.Queries; +using EntityDb.Npgsql.Transactions; +using EntityDb.SqlDb.Converters; +using EntityDb.SqlDb.Extensions; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace EntityDb.Npgsql.Provisioner.Extensions; + +internal static class ServiceCollectionExtensions +{ + public static void AddAutoProvisionNpgsqlTransactions( + this IServiceCollection serviceCollection, bool testMode = false) + { + serviceCollection.AddSqlDbEnvelopeService(); + + serviceCollection.Add, NpgsqlConverter> + ( + testMode ? ServiceLifetime.Singleton : ServiceLifetime.Transient + ); + + serviceCollection.Add + ( + testMode ? ServiceLifetime.Singleton : ServiceLifetime.Transient + ); + + serviceCollection.Add + ( + testMode ? ServiceLifetime.Singleton : ServiceLifetime.Transient, + serviceProvider => serviceProvider + .GetRequiredService() + .UseTestMode(testMode) + .UseAutoProvisioning(serviceProvider) + ); + } +} diff --git a/src/EntityDb.Npgsql.Provisioner/Program.cs b/src/EntityDb.Npgsql.Provisioner/Program.cs new file mode 100644 index 00000000..b3184bb2 --- /dev/null +++ b/src/EntityDb.Npgsql.Provisioner/Program.cs @@ -0,0 +1,29 @@ +using EntityDb.Npgsql.Provisioner.Commands; +using System.CommandLine; + +namespace EntityDb.Npgsql.Provisioner; + +internal static class Program +{ + public static Task Main(string[] args) + { +#if DEBUG + if (args.Length == 0) + { + Console.Write("Please enter args: "); + + var input = Console.ReadLine() ?? string.Empty; + + args = input.Split(' '); + } +#endif + + var rootCommand = new RootCommand(); + + CreateDatabase.AddTo(rootCommand); + CreateTables.AddTo(rootCommand); + CreateRole.AddTo(rootCommand); + + return rootCommand.InvokeAsync(args); + } +} diff --git a/src/EntityDb.Npgsql.Provisioner/Properties/AssemblyInfo.cs b/src/EntityDb.Npgsql.Provisioner/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..9375cfec --- /dev/null +++ b/src/EntityDb.Npgsql.Provisioner/Properties/AssemblyInfo.cs @@ -0,0 +1,5 @@ +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; + +[assembly: ExcludeFromCodeCoverage(Justification = "Provisioner is not production application code.")] +[assembly: InternalsVisibleTo("EntityDb.Common.Tests")] diff --git a/src/EntityDb.Npgsql.Provisioner/Transactions/AutoProvisionMongoDbTransactionRepositoryFactory.cs b/src/EntityDb.Npgsql.Provisioner/Transactions/AutoProvisionMongoDbTransactionRepositoryFactory.cs new file mode 100644 index 00000000..28a9b321 --- /dev/null +++ b/src/EntityDb.Npgsql.Provisioner/Transactions/AutoProvisionMongoDbTransactionRepositoryFactory.cs @@ -0,0 +1,83 @@ +using EntityDb.Npgsql.Provisioner.Extensions; +using EntityDb.Npgsql.Queries; +using EntityDb.SqlDb.Sessions; +using EntityDb.SqlDb.Transactions; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Npgsql; + +namespace EntityDb.Npgsql.Provisioner.Transactions; + +internal sealed class + AutoProvisionNpgsqlTransactionRepositoryFactory : SqlDbTransactionRepositoryFactoryWrapper +{ + private static readonly SemaphoreSlim Lock = new(1); + private static bool _provisioned; + private readonly ILogger _logger; + + public AutoProvisionNpgsqlTransactionRepositoryFactory + ( + ILogger logger, + ISqlDbTransactionRepositoryFactory npgsqlTransactionRepositoryFactory) : base(npgsqlTransactionRepositoryFactory) + { + _logger = logger; + } + + private async Task AcquireLock(CancellationToken cancellationToken) + { + _logger.LogInformation("Wait for Npgsql Auto-Provisioning Lock"); + + await Lock.WaitAsync(cancellationToken); + + _logger.LogInformation("Npgsql Auto-Provisioning Lock Acquired"); + } + + private void ReleaseLock() + { + _logger.LogInformation("Release Npgsql Auto-Provisioning Lock"); + + Lock.Release(); + + _logger.LogInformation("Npgsql Auto-Provisioning Lock Released"); + } + + public override async Task> CreateSession(SqlDbTransactionSessionOptions options, + CancellationToken cancellationToken) + { + var sqlDbSession = await base.CreateSession(options, cancellationToken); + + await AcquireLock(cancellationToken); + + if (_provisioned) + { + _logger.LogInformation("Npgsql already auto-provisioned."); + + ReleaseLock(); + + return sqlDbSession; + } + + var npgsqlConnection = new NpgsqlConnection(options.ConnectionString); + + await npgsqlConnection.OpenAsync(cancellationToken); + + await npgsqlConnection.ProvisionTables(cancellationToken); + + await npgsqlConnection.CloseAsync(); + + _provisioned = true; + + _logger.LogInformation("Npgsql has been auto-provisioned"); + + ReleaseLock(); + + return sqlDbSession; + } + + public static ISqlDbTransactionRepositoryFactory Create(IServiceProvider serviceProvider, + ISqlDbTransactionRepositoryFactory npgsqlTransactionRepositoryFactory) + { + return ActivatorUtilities.CreateInstance(serviceProvider, + npgsqlTransactionRepositoryFactory); + } +} diff --git a/src/EntityDb.Npgsql.Provisioner/packages.lock.json b/src/EntityDb.Npgsql.Provisioner/packages.lock.json new file mode 100644 index 00000000..8961f3f6 --- /dev/null +++ b/src/EntityDb.Npgsql.Provisioner/packages.lock.json @@ -0,0 +1,85 @@ +{ + "version": 1, + "dependencies": { + "net6.0": { + "System.CommandLine": { + "type": "Direct", + "requested": "[2.0.0-beta4.22272.1, )", + "resolved": "2.0.0-beta4.22272.1", + "contentHash": "1uqED/q2H0kKoLJ4+hI2iPSBSEdTuhfCYADeJrAqERmiGQ2NNacYKRNEQ+gFbU4glgVyK8rxI+ZOe1onEtr/Pg==" + }, + "System.CommandLine.NamingConventionBinder": { + "type": "Direct", + "requested": "[2.0.0-beta4.22272.1, )", + "resolved": "2.0.0-beta4.22272.1", + "contentHash": "ux2eUA/syF+JtlpMDc/Lsd6PBIBuwjH3AvHnestoh5uD0WKT5b+wkQxDWVCqp9qgVjMBTLNhX19ZYFtenunt9A==", + "dependencies": { + "System.CommandLine": "2.0.0-beta4.22272.1" + } + }, + "System.Linq.Async": { + "type": "Direct", + "requested": "[6.0.1, )", + "resolved": "6.0.1", + "contentHash": "0YhHcaroWpQ9UCot3Pizah7ryAzQhNvobLMSxeDIGmnXfkQn8u5owvpOH0K6EVB+z9L7u6Cc4W17Br/+jyttEQ==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "6.0.0" + } + }, + "Microsoft.Bcl.AsyncInterfaces": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==" + }, + "Npgsql": { + "type": "Transitive", + "resolved": "6.0.6", + "contentHash": "IIwnoJp0sFkhAydT/KKe/0NhlJKhYPIrXSE95AuU/2dqHNI9alxvjClJSGL+QE8NGqq1SFn+NenxVtm/JYsrJg==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + } + }, + "System.Runtime.CompilerServices.Unsafe": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==" + }, + "entitydb.abstractions": { + "type": "Project", + "dependencies": { + "System.Linq.Async": "6.0.1" + } + }, + "entitydb.common": { + "type": "Project", + "dependencies": { + "EntityDb.Abstractions": "1.0.0", + "System.Linq.Async": "6.0.1" + } + }, + "entitydb.json": { + "type": "Project", + "dependencies": { + "EntityDb.Common": "1.0.0", + "System.Linq.Async": "6.0.1" + } + }, + "entitydb.npgsql": { + "type": "Project", + "dependencies": { + "EntityDb.SqlDb": "1.0.0", + "Npgsql": "6.0.6", + "System.Linq.Async": "6.0.1" + } + }, + "entitydb.sqldb": { + "type": "Project", + "dependencies": { + "EntityDb.Common": "1.0.0", + "EntityDb.Json": "1.0.0", + "System.Linq.Async": "6.0.1" + } + } + } + } +} \ No newline at end of file diff --git a/src/EntityDb.Npgsql/Converters/NpgsqlConverter.cs b/src/EntityDb.Npgsql/Converters/NpgsqlConverter.cs new file mode 100644 index 00000000..b09491b1 --- /dev/null +++ b/src/EntityDb.Npgsql/Converters/NpgsqlConverter.cs @@ -0,0 +1,284 @@ +using EntityDb.Abstractions.ValueObjects; +using EntityDb.Npgsql.Queries; +using EntityDb.SqlDb.Converters; +using EntityDb.SqlDb.Documents; +using EntityDb.SqlDb.Documents.Lease; +using EntityDb.SqlDb.Documents.Tag; +using EntityDb.SqlDb.Queries.Definitions.Filter; +using EntityDb.SqlDb.Queries.Definitions.Sort; +using Npgsql; +using NpgsqlTypes; +using System.Collections; +using System.Data; +using System.Data.Common; +using System.Text; + +namespace EntityDb.Npgsql.Converters; + +internal class NpgsqlConverter : ISqlConverter +{ + public string SqlType => "Npgsql"; + + private static string GetProjection(IDocumentReader documentReader) + { + return string.Join + ( + ", ", + documentReader.GetPropertyNames() + ); + } + + private static string GetEqFilter(EqFilterDefinition eqFilterDefinition, NpgsqlParameterCollection parameters) + { + var parameterName = AddParameter(parameters, eqFilterDefinition.PropertyName, eqFilterDefinition.PropertyValue); + + return $"{eqFilterDefinition.PropertyName} = {parameterName}"; + } + + private static string GetInFitler(InFilterDefinition inFilterDefinition, NpgsqlParameterCollection parameters) + { + var parameterNames = AddParameters(parameters, inFilterDefinition.PropertyName, inFilterDefinition.PropertyValues); + + return $"{inFilterDefinition.PropertyName} IN ({string.Join(", ", parameterNames)})"; + } + + private static string GetAnyInFilter(AnyInFilterDefinition anyInFilterDefinition, NpgsqlParameterCollection parameters) + { + var parameterName = AddParameter(parameters, anyInFilterDefinition.PropertyName, anyInFilterDefinition.PropertyValues); + + return $"{anyInFilterDefinition.PropertyName} && {parameterName}"; + } + + private static string GetGteFilter(GteFilterDefinition gteFilterDefinition, NpgsqlParameterCollection parameters) + { + var parameterName = AddParameter(parameters, gteFilterDefinition.PropertyName, gteFilterDefinition.PropertyValue); + + return $"{gteFilterDefinition.PropertyName} >= {parameterName}"; + } + + private static string GetLteFilter(LteFilterDefinition lteFilterDefinition, NpgsqlParameterCollection parameters) + { + var parameterName = AddParameter(parameters, lteFilterDefinition.PropertyName, lteFilterDefinition.PropertyValue); + + return $"{lteFilterDefinition.PropertyName} <= {parameterName}"; + } + + private static string GetFilter(IFilterDefinition filterDefinition, NpgsqlParameterCollection parameters) + { + var filter = filterDefinition switch + { + AndFilterDefinition andFilterDefinition => string.Join + ( + " AND ", + andFilterDefinition.FilterDefinitions.Select(filterDefinition => GetFilter(filterDefinition, parameters)) + ), + + OrFilterDefinition orFilterDefinition => string.Join + ( + " OR ", + orFilterDefinition.FilterDefinitions.Select(filterDefinition => GetFilter(filterDefinition, parameters)) + ), + + NotFilterDefinition notFilterDefinition => $"NOT {GetFilter(notFilterDefinition.FilterDefinition, parameters)}", + + EqFilterDefinition eqFilterDefinition => GetEqFilter(eqFilterDefinition, parameters), + + InFilterDefinition inFilterDefinition => GetInFitler(inFilterDefinition, parameters), + + AnyInFilterDefinition anyInFilterDefinition => GetAnyInFilter(anyInFilterDefinition, parameters), + + GteFilterDefinition gteFilterDefinition => GetGteFilter(gteFilterDefinition, parameters), + + LteFilterDefinition lteFilterDefinition => GetLteFilter(lteFilterDefinition, parameters), + + _ => throw new NotSupportedException() + }; + + return $"({filter})"; + } + + private static string GetCollate(string tableName, NpgsqlQueryOptions? options, string propertyName) + { + if (tableName == LeaseDocument.TableName && propertyName == nameof(LeaseDocument.Value) && options?.LeaseValueSortCollation != null) + { + return $"COLLATE {options.LeaseValueSortCollation}"; + } + + if (tableName == TagDocument.TableName && propertyName == nameof(TagDocument.Value) && options?.TagValueSortCollation != null) + { + return $"COLLATE {options.TagValueSortCollation}"; + } + + return string.Empty; + } + + private static string GetAscSort(string tableName, NpgsqlQueryOptions? options, AscSortDefinition ascSortDefinition) + { + + return $"{ascSortDefinition.PropertyName} {GetCollate(tableName, options, ascSortDefinition.PropertyName)} ASC"; + } + + private static string GetDescSort(string tableName, NpgsqlQueryOptions? options, DescSortDefinition descSortDefinition) + { + return $"{descSortDefinition.PropertyName} {GetCollate(tableName, options, descSortDefinition.PropertyName)} DESC"; + } + + private static string GetSort(string tableName, NpgsqlQueryOptions? options, ISortDefinition sortDefinition) + { + return sortDefinition switch + { + CombineSortDefinition combineSortDefinition => string.Join + ( + ", ", + combineSortDefinition.SortDefinitions.Select(sortDefinition => GetSort(tableName, options, sortDefinition)) + ), + + AscSortDefinition ascSortDefinition => GetAscSort(tableName, options, ascSortDefinition), + + DescSortDefinition descSortDefinition => GetDescSort(tableName, options, descSortDefinition), + + _ => throw new NotSupportedException() + }; + } + + private static string AddParameter(NpgsqlParameterCollection parameters, string propertyName, object propertyValue) + { +#if DEBUG + var parameterName = $"@{propertyName}_{parameters.Count}"; +#else + var parameterName = $"@{parameters.Count}"; +#endif + + var parameter = propertyValue switch + { + IEnumerable ids => new NpgsqlParameter(parameterName, NpgsqlDbType.Array | NpgsqlDbType.Uuid) + { + Value = ids + .Select(id => id.Value) + .ToArray() + }, + Id id => new NpgsqlParameter(parameterName, NpgsqlDbType.Uuid) + { + Value = id.Value + }, + TimeStamp timeStamp => new NpgsqlParameter(parameterName, NpgsqlDbType.TimestampTz) + { + Value = timeStamp.Value + }, + VersionNumber versionNumber => new NpgsqlParameter(parameterName, NpgsqlDbType.Bigint) + { + Value = Convert.ToInt64(versionNumber.Value) + }, + string value => propertyName == nameof(ITransactionDocument.Data) + ? new NpgsqlParameter(parameterName, NpgsqlDbType.Jsonb) + { + Value = value + } + : new NpgsqlParameter(parameterName, NpgsqlDbType.Varchar) + { + Value = value + }, + _ => throw new NotSupportedException() + }; + + parameters.Add(parameter); + + return parameter.ParameterName; + } + + private static IEnumerable AddParameters(NpgsqlParameterCollection parameters, string propertyName, IEnumerable propertyValues) + { + foreach (var propertyValue in propertyValues) + { + yield return AddParameter(parameters, propertyName, propertyValue); + } + } + + public DbCommand ConvertInsert + ( + string tableName, + TDocument[] documents + ) + where TDocument : ITransactionDocument + { + var dbCommand = new NpgsqlCommand(); + + var columnNames = new List(); + var parameterNameSets = new List(documents.Length); + + foreach (var index in Enumerable.Range(0, documents.Length)) + { + var document = documents[index]; + + var documentDictionary = document.ToDictionary(); + + var parameterNames = new List(documentDictionary.Count); + + foreach (var (propertyName, propertyValue) in documentDictionary) + { + var parameterName = AddParameter(dbCommand.Parameters, propertyName, propertyValue); + + parameterNames.Add(parameterName); + + if (index == 0) + { + columnNames.Add(propertyName); + } + } + + parameterNameSets.Add($"({string.Join(", ", parameterNames)})"); + } + + dbCommand.CommandText = $"INSERT INTO {tableName} ({string.Join(", ", columnNames)}) VALUES {string.Join(", ", parameterNameSets)}"; + + return dbCommand; + } + + public DbCommand ConvertQuery + ( + string tableName, + IDocumentReader documentReader, + IFilterDefinition filterDefinition, + ISortDefinition? sortDefinition, + int? skip, + int? limit, + NpgsqlQueryOptions? options + ) + { + var dbQuery = new NpgsqlCommand(); + + var sqlBuilder = new StringBuilder($"SELECT {GetProjection(documentReader)} FROM {tableName} WHERE {GetFilter(filterDefinition, dbQuery.Parameters)}"); + + if (sortDefinition != null) + { + sqlBuilder.Append($" ORDER BY {GetSort(tableName, options, sortDefinition)}"); + } + + if (skip != null) + { + sqlBuilder.Append($" OFFSET {skip.Value}"); + } + + if (limit != null) + { + sqlBuilder.Append($" LIMIT {limit.Value}"); + } + + dbQuery.CommandText = sqlBuilder.ToString(); + + return dbQuery; + } + + public DbCommand ConvertDelete + ( + string tableName, + IFilterDefinition filterDefinition + ) + { + var dbCommand = new NpgsqlCommand(); + + dbCommand.CommandText = $"DELETE FROM {tableName} WHERE {GetFilter(filterDefinition, dbCommand.Parameters)}"; + + return dbCommand; + } +} diff --git a/src/EntityDb.Npgsql/EntityDb.Npgsql.csproj b/src/EntityDb.Npgsql/EntityDb.Npgsql.csproj new file mode 100644 index 00000000..3a19777f --- /dev/null +++ b/src/EntityDb.Npgsql/EntityDb.Npgsql.csproj @@ -0,0 +1,16 @@ + + + + EntityDb EventSourcing DDD CQRS Npgsql + An implementation of the EntityDb Transaction Repository interface, specifically for Npgsql. + + + + + + + + + + + diff --git a/src/EntityDb.Npgsql/Extensions/ServiceCollectionExtensions.cs b/src/EntityDb.Npgsql/Extensions/ServiceCollectionExtensions.cs new file mode 100644 index 00000000..b7146c40 --- /dev/null +++ b/src/EntityDb.Npgsql/Extensions/ServiceCollectionExtensions.cs @@ -0,0 +1,56 @@ +using EntityDb.Abstractions.Transactions; +using EntityDb.Common.Envelopes; +using EntityDb.Common.Extensions; +using EntityDb.Json.Envelopes; +using EntityDb.Npgsql.Converters; +using EntityDb.Npgsql.Queries; +using EntityDb.Npgsql.Transactions; +using EntityDb.SqlDb.Converters; +using EntityDb.SqlDb.Extensions; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using System.Diagnostics.CodeAnalysis; + +namespace EntityDb.Npgsql.Extensions; + +/// +/// Extensions for service collections. +/// +[ExcludeFromCodeCoverage(Justification = "All of the tests in this project are using the auto-provisioning variant.")] +public static class ServiceCollectionExtensions +{ + internal static void AddSqlDbEnvelopeService(this IServiceCollection serviceCollection) + { + serviceCollection.AddSingleton, JsonStringEnvelopeService>(); + } + + /// + /// Adds a production-ready implementation of to a service + /// collection. + /// + /// The service collection. + /// Modifies the behavior of the repository to accomodate tests. + public static void AddNpgsqlTransactions(this IServiceCollection serviceCollection, + bool testMode = false) + { + serviceCollection.AddSqlDbEnvelopeService(); + + serviceCollection.Add, NpgsqlConverter> + ( + testMode ? ServiceLifetime.Singleton : ServiceLifetime.Transient + ); + + serviceCollection.Add + ( + testMode ? ServiceLifetime.Singleton : ServiceLifetime.Transient + ); + + serviceCollection.Add + ( + testMode ? ServiceLifetime.Singleton : ServiceLifetime.Transient, + serviceProvider => serviceProvider + .GetRequiredService() + .UseTestMode(testMode) + ); + } +} diff --git a/src/EntityDb.Npgsql/Properties/AssemblyInfo.cs b/src/EntityDb.Npgsql/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..8f38b563 --- /dev/null +++ b/src/EntityDb.Npgsql/Properties/AssemblyInfo.cs @@ -0,0 +1,5 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] +[assembly: InternalsVisibleTo("EntityDb.Npgsql.Provisioner")] +[assembly: InternalsVisibleTo("EntityDb.Npgsql.Tests")] diff --git a/src/EntityDb.Npgsql/Queries/NpgsqlQueryOptions.cs b/src/EntityDb.Npgsql/Queries/NpgsqlQueryOptions.cs new file mode 100644 index 00000000..46f80ebe --- /dev/null +++ b/src/EntityDb.Npgsql/Queries/NpgsqlQueryOptions.cs @@ -0,0 +1,20 @@ +using EntityDb.Abstractions.Leases; +using EntityDb.Abstractions.Tags; + +namespace EntityDb.Npgsql.Queries; + +/// +/// Defines query options for the Npgsql driver. +/// +public class NpgsqlQueryOptions +{ + /// + /// Defines the collation for sorting on . + /// + public string? LeaseValueSortCollation { get; set; } + + /// + /// Defines teh collation for sorting on . + /// + public string? TagValueSortCollation { get; set; } +} diff --git a/src/EntityDb.Npgsql/Transactions/NpgsqlTransactionRepositoryFactory.cs b/src/EntityDb.Npgsql/Transactions/NpgsqlTransactionRepositoryFactory.cs new file mode 100644 index 00000000..44ffcc0e --- /dev/null +++ b/src/EntityDb.Npgsql/Transactions/NpgsqlTransactionRepositoryFactory.cs @@ -0,0 +1,64 @@ +using EntityDb.Abstractions.Transactions; +using EntityDb.Common.Disposables; +using EntityDb.Common.Envelopes; +using EntityDb.Common.Transactions; +using EntityDb.Npgsql.Queries; +using EntityDb.SqlDb.Sessions; +using EntityDb.SqlDb.Transactions; +using Microsoft.Extensions.Options; +using Npgsql; + +namespace EntityDb.Npgsql.Transactions; + +internal class NpgsqlTransactionRepositoryFactory : DisposableResourceBaseClass, ISqlDbTransactionRepositoryFactory +{ + private readonly IEnvelopeService _envelopeService; + private readonly IOptionsFactory _optionsFactory; + private readonly IServiceProvider _serviceProvider; + + public NpgsqlTransactionRepositoryFactory + ( + IServiceProvider serviceProvider, + IOptionsFactory optionsFactory, + IEnvelopeService envelopeService + ) + { + _serviceProvider = serviceProvider; + _optionsFactory = optionsFactory; + _envelopeService = envelopeService; + } + + public SqlDbTransactionSessionOptions GetTransactionSessionOptions(string transactionSessionOptionsName) + { + return _optionsFactory.Create(transactionSessionOptionsName); + } + + public async Task> CreateSession(SqlDbTransactionSessionOptions options, + CancellationToken cancellationToken) + { + var npgsqlConnection = new NpgsqlConnection(options.ConnectionString); + + await npgsqlConnection.OpenAsync(cancellationToken); + + return SqlDbSession.Create + ( + _serviceProvider, + npgsqlConnection, + options + ); + } + + public ITransactionRepository CreateRepository + ( + ISqlDbSession sqlDbSession + ) + { + var npgsqlTransactionRepository = new SqlDbTransactionRepository + ( + sqlDbSession, + _envelopeService + ); + + return TryCatchTransactionRepository.Create(_serviceProvider, npgsqlTransactionRepository); + } +} diff --git a/src/EntityDb.Npgsql/packages.lock.json b/src/EntityDb.Npgsql/packages.lock.json new file mode 100644 index 00000000..a87c03a6 --- /dev/null +++ b/src/EntityDb.Npgsql/packages.lock.json @@ -0,0 +1,63 @@ +{ + "version": 1, + "dependencies": { + "net6.0": { + "Npgsql": { + "type": "Direct", + "requested": "[6.0.6, )", + "resolved": "6.0.6", + "contentHash": "IIwnoJp0sFkhAydT/KKe/0NhlJKhYPIrXSE95AuU/2dqHNI9alxvjClJSGL+QE8NGqq1SFn+NenxVtm/JYsrJg==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + } + }, + "System.Linq.Async": { + "type": "Direct", + "requested": "[6.0.1, )", + "resolved": "6.0.1", + "contentHash": "0YhHcaroWpQ9UCot3Pizah7ryAzQhNvobLMSxeDIGmnXfkQn8u5owvpOH0K6EVB+z9L7u6Cc4W17Br/+jyttEQ==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "6.0.0" + } + }, + "Microsoft.Bcl.AsyncInterfaces": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==" + }, + "System.Runtime.CompilerServices.Unsafe": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==" + }, + "entitydb.abstractions": { + "type": "Project", + "dependencies": { + "System.Linq.Async": "6.0.1" + } + }, + "entitydb.common": { + "type": "Project", + "dependencies": { + "EntityDb.Abstractions": "1.0.0", + "System.Linq.Async": "6.0.1" + } + }, + "entitydb.json": { + "type": "Project", + "dependencies": { + "EntityDb.Common": "1.0.0", + "System.Linq.Async": "6.0.1" + } + }, + "entitydb.sqldb": { + "type": "Project", + "dependencies": { + "EntityDb.Common": "1.0.0", + "EntityDb.Json": "1.0.0", + "System.Linq.Async": "6.0.1" + } + } + } + } +} \ No newline at end of file diff --git a/src/EntityDb.Redis/ConnectionMultiplexers/ConnectionMultiplexerPool.cs b/src/EntityDb.Redis/ConnectionMultiplexers/ConnectionMultiplexerPool.cs index 079fd076..87ad8189 100644 --- a/src/EntityDb.Redis/ConnectionMultiplexers/ConnectionMultiplexerPool.cs +++ b/src/EntityDb.Redis/ConnectionMultiplexers/ConnectionMultiplexerPool.cs @@ -1,8 +1,6 @@ using EntityDb.Common.Disposables; using StackExchange.Redis; using System.Collections.Concurrent; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.Redis.ConnectionMultiplexers; diff --git a/src/EntityDb.Redis/EntityDb.Redis.csproj b/src/EntityDb.Redis/EntityDb.Redis.csproj index 5ca3c7b1..923c81a5 100644 --- a/src/EntityDb.Redis/EntityDb.Redis.csproj +++ b/src/EntityDb.Redis/EntityDb.Redis.csproj @@ -7,11 +7,12 @@ - + - + + \ No newline at end of file diff --git a/src/EntityDb.Redis/Extensions/ServiceCollectionExtensions.cs b/src/EntityDb.Redis/Extensions/ServiceCollectionExtensions.cs index 5f2ed35b..c184b7e1 100644 --- a/src/EntityDb.Redis/Extensions/ServiceCollectionExtensions.cs +++ b/src/EntityDb.Redis/Extensions/ServiceCollectionExtensions.cs @@ -1,13 +1,12 @@ using EntityDb.Abstractions.Snapshots; using EntityDb.Common.Envelopes; using EntityDb.Common.Extensions; +using EntityDb.Json.Envelopes; using EntityDb.Redis.ConnectionMultiplexers; -using EntityDb.Redis.Envelopes; using EntityDb.Redis.Snapshots; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using System.Diagnostics.CodeAnalysis; -using System.Text.Json; namespace EntityDb.Redis.Extensions; @@ -19,7 +18,7 @@ public static class ServiceCollectionExtensions { internal static void AddJsonElementEnvelopeService(this IServiceCollection serviceCollection) { - serviceCollection.AddSingleton, JsonElementEnvelopeService>(); + serviceCollection.AddSingleton, JsonBytesEnvelopeService>(); } /// diff --git a/src/EntityDb.Redis/Sessions/IRedisSession.cs b/src/EntityDb.Redis/Sessions/IRedisSession.cs index 16527af5..9f936efd 100644 --- a/src/EntityDb.Redis/Sessions/IRedisSession.cs +++ b/src/EntityDb.Redis/Sessions/IRedisSession.cs @@ -1,7 +1,6 @@ using EntityDb.Abstractions.Disposables; using EntityDb.Abstractions.ValueObjects; using StackExchange.Redis; -using System.Threading.Tasks; namespace EntityDb.Redis.Sessions; diff --git a/src/EntityDb.Redis/Sessions/RedisSession.cs b/src/EntityDb.Redis/Sessions/RedisSession.cs index 86ee4b1f..78a24705 100644 --- a/src/EntityDb.Redis/Sessions/RedisSession.cs +++ b/src/EntityDb.Redis/Sessions/RedisSession.cs @@ -4,9 +4,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using StackExchange.Redis; -using System; -using System.Linq; -using System.Threading.Tasks; namespace EntityDb.Redis.Sessions; diff --git a/src/EntityDb.Redis/Snapshots/RedisSnapshotRepository.cs b/src/EntityDb.Redis/Snapshots/RedisSnapshotRepository.cs index 3c809237..4c43a6ec 100644 --- a/src/EntityDb.Redis/Snapshots/RedisSnapshotRepository.cs +++ b/src/EntityDb.Redis/Snapshots/RedisSnapshotRepository.cs @@ -2,22 +2,18 @@ using EntityDb.Abstractions.ValueObjects; using EntityDb.Common.Disposables; using EntityDb.Common.Envelopes; -using EntityDb.Common.Extensions; using EntityDb.Redis.Sessions; -using System.Text.Json; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.Redis.Snapshots; internal class RedisSnapshotRepository : DisposableResourceBaseClass, ISnapshotRepository { - private readonly IEnvelopeService _envelopeService; + private readonly IEnvelopeService _envelopeService; private readonly IRedisSession _redisSession; public RedisSnapshotRepository ( - IEnvelopeService envelopeService, + IEnvelopeService envelopeService, IRedisSession redisSession ) { @@ -29,7 +25,7 @@ public async Task PutSnapshot(Pointer snapshotPointer, TSnapshot snapshot, CancellationToken cancellationToken = default) { var snapshotValue = _envelopeService - .DeconstructAndSerialize(snapshot); + .Serialize(snapshot); return await _redisSession.Insert(snapshotPointer, snapshotValue).WaitAsync(cancellationToken); } @@ -45,7 +41,7 @@ public async Task PutSnapshot(Pointer snapshotPointer, TSnapshot snapshot, } return _envelopeService - .DeserializeAndReconstruct(snapshotValue); + .Deserialize(snapshotValue!); } public Task DeleteSnapshots(Pointer[] snapshotPointers, CancellationToken cancellationToken = default) diff --git a/src/EntityDb.Redis/Snapshots/RedisSnapshotRepositoryFactory.cs b/src/EntityDb.Redis/Snapshots/RedisSnapshotRepositoryFactory.cs index 057be347..7426383f 100644 --- a/src/EntityDb.Redis/Snapshots/RedisSnapshotRepositoryFactory.cs +++ b/src/EntityDb.Redis/Snapshots/RedisSnapshotRepositoryFactory.cs @@ -6,10 +6,6 @@ using EntityDb.Redis.Sessions; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; -using System; -using System.Text.Json; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.Redis.Snapshots; @@ -17,7 +13,7 @@ internal class RedisSnapshotRepositoryFactory : DisposableResourceBas ISnapshotRepositoryFactory { private readonly ConnectionMultiplexerFactory _connectionMultiplexerFactory; - private readonly IEnvelopeService _envelopeService; + private readonly IEnvelopeService _envelopeService; private readonly IOptionsFactory> _optionsFactory; private readonly IServiceProvider _serviceProvider; @@ -26,7 +22,7 @@ public RedisSnapshotRepositoryFactory IServiceProvider serviceProvider, ConnectionMultiplexerFactory connectionMultiplexerFactory, IOptionsFactory> optionsFactory, - IEnvelopeService envelopeService + IEnvelopeService envelopeService ) { _serviceProvider = serviceProvider; diff --git a/src/EntityDb.Redis/packages.lock.json b/src/EntityDb.Redis/packages.lock.json index 33cee272..597ce2b5 100644 --- a/src/EntityDb.Redis/packages.lock.json +++ b/src/EntityDb.Redis/packages.lock.json @@ -12,6 +12,20 @@ "System.Diagnostics.PerformanceCounter": "5.0.0" } }, + "System.Linq.Async": { + "type": "Direct", + "requested": "[6.0.1, )", + "resolved": "6.0.1", + "contentHash": "0YhHcaroWpQ9UCot3Pizah7ryAzQhNvobLMSxeDIGmnXfkQn8u5owvpOH0K6EVB+z9L7u6Cc4W17Br/+jyttEQ==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "6.0.0" + } + }, + "Microsoft.Bcl.AsyncInterfaces": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==" + }, "Microsoft.NETCore.Platforms": { "type": "Transitive", "resolved": "5.0.0", @@ -112,12 +126,23 @@ } }, "entitydb.abstractions": { - "type": "Project" + "type": "Project", + "dependencies": { + "System.Linq.Async": "6.0.1" + } }, "entitydb.common": { "type": "Project", "dependencies": { - "EntityDb.Abstractions": "1.0.0" + "EntityDb.Abstractions": "1.0.0", + "System.Linq.Async": "6.0.1" + } + }, + "entitydb.json": { + "type": "Project", + "dependencies": { + "EntityDb.Common": "1.0.0", + "System.Linq.Async": "6.0.1" } } } diff --git a/src/EntityDb.SqlDb/Commands/DeleteDocumentsCommand.cs b/src/EntityDb.SqlDb/Commands/DeleteDocumentsCommand.cs new file mode 100644 index 00000000..3cfadf7f --- /dev/null +++ b/src/EntityDb.SqlDb/Commands/DeleteDocumentsCommand.cs @@ -0,0 +1,18 @@ +using EntityDb.SqlDb.Queries.Definitions.Filter; +using EntityDb.SqlDb.Sessions; + +namespace EntityDb.SqlDb.Commands; + +internal record DeleteDocumentsCommand +( + string TableName, + IFilterDefinition FilterDefinition +) +{ + public async Task Execute(ISqlDbSession sqlDbSession, CancellationToken cancellationToken) + where TOptions : class + { + await sqlDbSession + .Delete(TableName, FilterDefinition, cancellationToken); + } +} diff --git a/src/EntityDb.SqlDb/Commands/InsertDocumentsCommand.cs b/src/EntityDb.SqlDb/Commands/InsertDocumentsCommand.cs new file mode 100644 index 00000000..66962216 --- /dev/null +++ b/src/EntityDb.SqlDb/Commands/InsertDocumentsCommand.cs @@ -0,0 +1,19 @@ +using EntityDb.SqlDb.Documents; +using EntityDb.SqlDb.Sessions; + +namespace EntityDb.SqlDb.Commands; + +internal record InsertDocumentsCommand +( + string TableName, + TDocument[] Documents +) + where TDocument : ITransactionDocument +{ + public async Task Execute(ISqlDbSession sqlDbSession, CancellationToken cancellationToken) + where TOptions : class + { + await sqlDbSession + .Insert(TableName, Documents, cancellationToken); + } +} diff --git a/src/EntityDb.SqlDb/Converters/ISqlConverter.cs b/src/EntityDb.SqlDb/Converters/ISqlConverter.cs new file mode 100644 index 00000000..a089688d --- /dev/null +++ b/src/EntityDb.SqlDb/Converters/ISqlConverter.cs @@ -0,0 +1,30 @@ +using EntityDb.SqlDb.Documents; +using EntityDb.SqlDb.Queries.Definitions.Filter; +using EntityDb.SqlDb.Queries.Definitions.Sort; +using System.Data.Common; + +namespace EntityDb.SqlDb.Converters; + +internal interface ISqlConverter +{ + string SqlType { get; } + + DbCommand ConvertInsert(string tableName, TDocument[] documents) where TDocument : ITransactionDocument; + + DbCommand ConvertQuery + ( + string tableName, + IDocumentReader documentReader, + IFilterDefinition filterDefinition, + ISortDefinition? sortDefinition, + int? skip, + int? limit, + TOptions? options + ); + + DbCommand ConvertDelete + ( + string tableName, + IFilterDefinition filterDefinition + ); +} diff --git a/src/EntityDb.SqlDb/Documents/AgentSignature/AgentSignatureDataDocumentReader.cs b/src/EntityDb.SqlDb/Documents/AgentSignature/AgentSignatureDataDocumentReader.cs new file mode 100644 index 00000000..3fba7946 --- /dev/null +++ b/src/EntityDb.SqlDb/Documents/AgentSignature/AgentSignatureDataDocumentReader.cs @@ -0,0 +1,23 @@ +using System.Data.Common; + +namespace EntityDb.SqlDb.Documents.AgentSignature; + +internal class AgentSignatureDataDocumentReader : AgentSignatureDocumentReaderBase, IDocumentReader +{ + private static readonly string[] _propertyNames = + { + nameof(AgentSignatureDocument.Data), + }; + + public AgentSignatureDataDocumentReader() : base(_propertyNames) + { + } + + public async Task Read(DbDataReader dbDataReader, CancellationToken cancellationToken) + { + return new AgentSignatureDocument + { + Data = await dbDataReader.GetFieldValueAsync(_dataOrdinal) + }; + } +} diff --git a/src/EntityDb.SqlDb/Documents/AgentSignature/AgentSignatureDocument.cs b/src/EntityDb.SqlDb/Documents/AgentSignature/AgentSignatureDocument.cs new file mode 100644 index 00000000..c2656b49 --- /dev/null +++ b/src/EntityDb.SqlDb/Documents/AgentSignature/AgentSignatureDocument.cs @@ -0,0 +1,82 @@ +using EntityDb.Abstractions.Queries; +using EntityDb.Abstractions.Transactions; +using EntityDb.Abstractions.ValueObjects; +using EntityDb.Common.Envelopes; +using EntityDb.SqlDb.Commands; +using EntityDb.SqlDb.Queries; +using EntityDb.SqlDb.Queries.FilterBuilders; +using EntityDb.SqlDb.Queries.SortBuilders; + +namespace EntityDb.SqlDb.Documents.AgentSignature; + +internal sealed record AgentSignatureDocument : DocumentBase, IEntitiesDocument +{ + public static string TableName => "AgentSignatures"; + + private static readonly AgentSignatureFilterBuilder FilterBuilder = new(); + + private static readonly AgentSignatureSortBuilder SortBuilder = new(); + + public Id[] EntityIds { get; init; } = Array.Empty(); + + public static IDocumentReader DocumentReader { get; } = new AgentSignatureDocumentReader(); + + public static IDocumentReader TransactionIdDocumentReader { get; } = new AgentSignatureTransactionIdDocumentReader(); + + public static IDocumentReader DataDocumentReader { get; } = new AgentSignatureDataDocumentReader(); + + public static IDocumentReader EntityIdsDocumentReader { get; } = new AgentSignatureEntityIdsDocumentReader(); + + public static InsertDocumentsCommand GetInsert + ( + IEnvelopeService envelopeService, + ITransaction transaction + ) + { + return new InsertDocumentsCommand + ( + TableName, + new[] + { + new AgentSignatureDocument + { + TransactionTimeStamp = transaction.TimeStamp, + TransactionId = transaction.Id, + EntityIds = transaction.Steps + .Select(transactionStep => transactionStep.EntityId) + .Distinct() + .ToArray(), + DataType = transaction.AgentSignature.GetType().Name, + Data = envelopeService.Serialize(transaction.AgentSignature) + } + } + ); + } + + public static DocumentQuery GetQuery + ( + IAgentSignatureQuery agentSignatureQuery + ) + { + return new DocumentQuery + ( + agentSignatureQuery.GetFilter(FilterBuilder), + agentSignatureQuery.GetSort(SortBuilder), + agentSignatureQuery.Skip, + agentSignatureQuery.Take, + agentSignatureQuery.Options + ); + } + + public Dictionary ToDictionary() + { + return new Dictionary + { + [nameof(TransactionId)] = TransactionId, + [nameof(TransactionTimeStamp)] = TransactionTimeStamp, + [nameof(EntityIds)] = EntityIds, + [nameof(DataType)] = DataType, + [nameof(Data)] = Data, + }; + } +} diff --git a/src/EntityDb.SqlDb/Documents/AgentSignature/AgentSignatureDocumentReader.cs b/src/EntityDb.SqlDb/Documents/AgentSignature/AgentSignatureDocumentReader.cs new file mode 100644 index 00000000..f9dd2a39 --- /dev/null +++ b/src/EntityDb.SqlDb/Documents/AgentSignature/AgentSignatureDocumentReader.cs @@ -0,0 +1,34 @@ +using EntityDb.Abstractions.ValueObjects; +using System.Data.Common; + +namespace EntityDb.SqlDb.Documents.AgentSignature; + +internal class AgentSignatureDocumentReader : AgentSignatureDocumentReaderBase, IDocumentReader +{ + private static readonly string[] _propertyNames = + { + nameof(AgentSignatureDocument.TransactionId), + nameof(AgentSignatureDocument.TransactionTimeStamp), + nameof(AgentSignatureDocument.EntityIds), + nameof(AgentSignatureDocument.DataType), + nameof(AgentSignatureDocument.Data), + }; + + public AgentSignatureDocumentReader() : base(_propertyNames) + { + } + + public async Task Read(DbDataReader dbDataReader, CancellationToken cancellationToken) + { + return new AgentSignatureDocument + { + TransactionId = new Id(await dbDataReader.GetFieldValueAsync(_transactionIdOrdinal)), + TransactionTimeStamp = new TimeStamp(await dbDataReader.GetFieldValueAsync(_transactionTimeStampOrdinal)), + EntityIds = (await dbDataReader.GetFieldValueAsync(_entityIdsOrdinal)) + .Select(guid => new Id(guid)) + .ToArray(), + DataType = await dbDataReader.GetFieldValueAsync(_dataTypeOrdinal), + Data = await dbDataReader.GetFieldValueAsync(_dataOrdinal), + }; + } +} diff --git a/src/EntityDb.SqlDb/Documents/AgentSignature/AgentSignatureDocumentReaderBase.cs b/src/EntityDb.SqlDb/Documents/AgentSignature/AgentSignatureDocumentReaderBase.cs new file mode 100644 index 00000000..1e8b0040 --- /dev/null +++ b/src/EntityDb.SqlDb/Documents/AgentSignature/AgentSignatureDocumentReaderBase.cs @@ -0,0 +1,25 @@ +namespace EntityDb.SqlDb.Documents.AgentSignature; + +internal abstract class AgentSignatureDocumentReaderBase +{ + private readonly string[] _propertyNames; + + protected readonly int _transactionIdOrdinal; + protected readonly int _transactionTimeStampOrdinal; + protected readonly int _entityIdsOrdinal; + protected readonly int _dataTypeOrdinal; + protected readonly int _dataOrdinal; + + public string[] GetPropertyNames() => _propertyNames; + + protected AgentSignatureDocumentReaderBase(string[] propertyNames) + { + _propertyNames = propertyNames; + + _transactionIdOrdinal = Array.IndexOf(_propertyNames, nameof(AgentSignatureDocument.TransactionId)); + _transactionTimeStampOrdinal = Array.IndexOf(_propertyNames, nameof(AgentSignatureDocument.TransactionTimeStamp)); + _entityIdsOrdinal = Array.IndexOf(_propertyNames, nameof(AgentSignatureDocument.EntityIds)); + _dataTypeOrdinal = Array.IndexOf(_propertyNames, nameof(AgentSignatureDocument.DataType)); + _dataOrdinal = Array.IndexOf(_propertyNames, nameof(AgentSignatureDocument.Data)); + } +} diff --git a/src/EntityDb.SqlDb/Documents/AgentSignature/AgentSignatureEntityIdsDocumentReader.cs b/src/EntityDb.SqlDb/Documents/AgentSignature/AgentSignatureEntityIdsDocumentReader.cs new file mode 100644 index 00000000..b18758d5 --- /dev/null +++ b/src/EntityDb.SqlDb/Documents/AgentSignature/AgentSignatureEntityIdsDocumentReader.cs @@ -0,0 +1,26 @@ +using EntityDb.Abstractions.ValueObjects; +using System.Data.Common; + +namespace EntityDb.SqlDb.Documents.AgentSignature; + +internal class AgentSignatureEntityIdsDocumentReader : AgentSignatureDocumentReaderBase, IDocumentReader +{ + private static readonly string[] _propertyNames = + { + nameof(AgentSignatureDocument.EntityIds), + }; + + public AgentSignatureEntityIdsDocumentReader() : base(_propertyNames) + { + } + + public async Task Read(DbDataReader dbDataReader, CancellationToken cancellationToken) + { + return new AgentSignatureDocument + { + EntityIds = (await dbDataReader.GetFieldValueAsync(_entityIdsOrdinal)) + .Select(guid => new Id(guid)) + .ToArray() + }; + } +} diff --git a/src/EntityDb.SqlDb/Documents/AgentSignature/AgentSignatureTransactionIdDocumentReader.cs b/src/EntityDb.SqlDb/Documents/AgentSignature/AgentSignatureTransactionIdDocumentReader.cs new file mode 100644 index 00000000..09d8eb55 --- /dev/null +++ b/src/EntityDb.SqlDb/Documents/AgentSignature/AgentSignatureTransactionIdDocumentReader.cs @@ -0,0 +1,24 @@ +using EntityDb.Abstractions.ValueObjects; +using System.Data.Common; + +namespace EntityDb.SqlDb.Documents.AgentSignature; + +internal class AgentSignatureTransactionIdDocumentReader : AgentSignatureDocumentReaderBase, IDocumentReader +{ + private static readonly string[] _propertyNames = + { + nameof(AgentSignatureDocument.TransactionId), + }; + + public AgentSignatureTransactionIdDocumentReader() : base(_propertyNames) + { + } + + public async Task Read(DbDataReader dbDataReader, CancellationToken cancellationToken) + { + return new AgentSignatureDocument + { + TransactionId = new Id(await dbDataReader.GetFieldValueAsync(_transactionIdOrdinal)) + }; + } +} diff --git a/src/EntityDb.SqlDb/Documents/Command/CommandDataDocumentReader.cs b/src/EntityDb.SqlDb/Documents/Command/CommandDataDocumentReader.cs new file mode 100644 index 00000000..16e4ade5 --- /dev/null +++ b/src/EntityDb.SqlDb/Documents/Command/CommandDataDocumentReader.cs @@ -0,0 +1,23 @@ +using System.Data.Common; + +namespace EntityDb.SqlDb.Documents.Command; + +internal class CommandDataDocumentReader : CommandDocumentReaderBase, IDocumentReader +{ + private static readonly string[] _propertyNames = + { + nameof(CommandDocument.Data), + }; + + public CommandDataDocumentReader() : base(_propertyNames) + { + } + + public async Task Read(DbDataReader dbDataReader, CancellationToken cancellationToken) + { + return new CommandDocument + { + Data = await dbDataReader.GetFieldValueAsync(_dataOrdinal) + }; + } +} diff --git a/src/EntityDb.SqlDb/Documents/Command/CommandDocument.cs b/src/EntityDb.SqlDb/Documents/Command/CommandDocument.cs new file mode 100644 index 00000000..bf63cb44 --- /dev/null +++ b/src/EntityDb.SqlDb/Documents/Command/CommandDocument.cs @@ -0,0 +1,109 @@ +using EntityDb.Abstractions.Queries; +using EntityDb.Abstractions.Transactions; +using EntityDb.Abstractions.Transactions.Steps; +using EntityDb.Abstractions.ValueObjects; +using EntityDb.Common.Envelopes; +using EntityDb.Common.Queries; +using EntityDb.SqlDb.Commands; +using EntityDb.SqlDb.Queries; +using EntityDb.SqlDb.Queries.FilterBuilders; +using EntityDb.SqlDb.Queries.SortBuilders; +using EntityDb.SqlDb.Sessions; + +namespace EntityDb.SqlDb.Documents.Command; + +internal sealed record CommandDocument : DocumentBase, IEntityDocument +{ + public static string TableName => "Commands"; + + private static readonly CommandFilterBuilder FilterBuilder = new(); + + private static readonly CommandSortBuilder SortBuilder = new(); + + private static readonly IDocumentReader EntityVersionNumberDocumentReader = new CommandEntityVersionNumberDocumentReader(); + + public static IDocumentReader DocumentReader { get; } = new CommandDocumentReader(); + + public static IDocumentReader TransactionIdDocumentReader { get; } = new CommandTransactionIdDocumentReader(); + + public static IDocumentReader DataDocumentReader { get; } = new CommandDataDocumentReader(); + + public static IDocumentReader EntityIdDocumentReader { get; } = new CommandEntityIdDocumentReader(); + + public Id EntityId { get; init; } + public VersionNumber EntityVersionNumber { get; init; } + + public static InsertDocumentsCommand GetInsert + ( + IEnvelopeService envelopeService, + ITransaction transaction, + IAppendCommandTransactionStep appendCommandTransactionStep + ) + { + return new InsertDocumentsCommand + ( + TableName, + new[] + { + new CommandDocument + { + TransactionTimeStamp = transaction.TimeStamp, + TransactionId = transaction.Id, + EntityId = appendCommandTransactionStep.EntityId, + EntityVersionNumber = appendCommandTransactionStep.EntityVersionNumber, + DataType = appendCommandTransactionStep.Command.GetType().Name, + Data = envelopeService.Serialize(appendCommandTransactionStep.Command) + } + } + ); + } + + public static DocumentQuery GetQuery + ( + ICommandQuery commandQuery + ) + { + return new DocumentQuery + ( + commandQuery.GetFilter(FilterBuilder), + commandQuery.GetSort(SortBuilder), + commandQuery.Skip, + commandQuery.Take, + commandQuery.Options + ); + } + + public static async Task GetLastEntityVersionNumber + ( + ISqlDbSession sqlDbSession, + Id entityId, + CancellationToken cancellationToken + ) + where TOptions : class + { + var commandQuery = new GetLastEntityCommandQuery(entityId); + + var documentQuery = GetQuery(commandQuery); + + var document = await documentQuery + .Execute(sqlDbSession, EntityVersionNumberDocumentReader, cancellationToken) + .SingleOrDefaultAsync(cancellationToken); + + return document is null + ? default + : document.EntityVersionNumber; + } + + public Dictionary ToDictionary() + { + return new Dictionary + { + [nameof(TransactionId)] = TransactionId, + [nameof(TransactionTimeStamp)] = TransactionTimeStamp, + [nameof(EntityId)] = EntityId, + [nameof(EntityVersionNumber)] = EntityVersionNumber, + [nameof(DataType)] = DataType, + [nameof(Data)] = Data, + }; + } +} diff --git a/src/EntityDb.SqlDb/Documents/Command/CommandDocumentReader.cs b/src/EntityDb.SqlDb/Documents/Command/CommandDocumentReader.cs new file mode 100644 index 00000000..b00efe12 --- /dev/null +++ b/src/EntityDb.SqlDb/Documents/Command/CommandDocumentReader.cs @@ -0,0 +1,34 @@ +using EntityDb.Abstractions.ValueObjects; +using System.Data.Common; + +namespace EntityDb.SqlDb.Documents.Command; + +internal class CommandDocumentReader : CommandDocumentReaderBase, IDocumentReader +{ + private static readonly string[] _propertyNames = + { + nameof(CommandDocument.TransactionId), + nameof(CommandDocument.TransactionTimeStamp), + nameof(CommandDocument.EntityId), + nameof(CommandDocument.EntityVersionNumber), + nameof(CommandDocument.DataType), + nameof(CommandDocument.Data), + }; + + public CommandDocumentReader() : base(_propertyNames) + { + } + + public async Task Read(DbDataReader dbDataReader, CancellationToken cancellationToken) + { + return new CommandDocument + { + TransactionId = new Id(await dbDataReader.GetFieldValueAsync(_transactionIdOrdinal)), + TransactionTimeStamp = new TimeStamp(await dbDataReader.GetFieldValueAsync(_transactionTimeStampOrdinal)), + EntityId = new Id(await dbDataReader.GetFieldValueAsync(_entityIdOrdinal)), + EntityVersionNumber = new VersionNumber(Convert.ToUInt64(await dbDataReader.GetFieldValueAsync(_entityVersionNumberOrdinal))), + DataType = await dbDataReader.GetFieldValueAsync(_dataTypeOrdinal), + Data = await dbDataReader.GetFieldValueAsync(_dataOrdinal), + }; + } +} diff --git a/src/EntityDb.SqlDb/Documents/Command/CommandDocumentReaderBase.cs b/src/EntityDb.SqlDb/Documents/Command/CommandDocumentReaderBase.cs new file mode 100644 index 00000000..f62c15c6 --- /dev/null +++ b/src/EntityDb.SqlDb/Documents/Command/CommandDocumentReaderBase.cs @@ -0,0 +1,27 @@ +namespace EntityDb.SqlDb.Documents.Command; + +internal abstract class CommandDocumentReaderBase +{ + private readonly string[] _propertyNames; + + protected readonly int _transactionIdOrdinal; + protected readonly int _transactionTimeStampOrdinal; + protected readonly int _entityIdOrdinal; + protected readonly int _entityVersionNumberOrdinal; + protected readonly int _dataTypeOrdinal; + protected readonly int _dataOrdinal; + + public string[] GetPropertyNames() => _propertyNames; + + protected CommandDocumentReaderBase(string[] propertyNames) + { + _propertyNames = propertyNames; + + _transactionIdOrdinal = Array.IndexOf(_propertyNames, nameof(CommandDocument.TransactionId)); + _transactionTimeStampOrdinal = Array.IndexOf(_propertyNames, nameof(CommandDocument.TransactionTimeStamp)); + _entityIdOrdinal = Array.IndexOf(_propertyNames, nameof(CommandDocument.EntityId)); + _entityVersionNumberOrdinal = Array.IndexOf(_propertyNames, nameof(CommandDocument.EntityVersionNumber)); + _dataTypeOrdinal = Array.IndexOf(_propertyNames, nameof(CommandDocument.DataType)); + _dataOrdinal = Array.IndexOf(_propertyNames, nameof(CommandDocument.Data)); + } +} diff --git a/src/EntityDb.SqlDb/Documents/Command/CommandEntityIdDocumentReader.cs b/src/EntityDb.SqlDb/Documents/Command/CommandEntityIdDocumentReader.cs new file mode 100644 index 00000000..ea436dbb --- /dev/null +++ b/src/EntityDb.SqlDb/Documents/Command/CommandEntityIdDocumentReader.cs @@ -0,0 +1,24 @@ +using EntityDb.Abstractions.ValueObjects; +using System.Data.Common; + +namespace EntityDb.SqlDb.Documents.Command; + +internal class CommandEntityIdDocumentReader : CommandDocumentReaderBase, IDocumentReader +{ + private static readonly string[] _propertyNames = + { + nameof(CommandDocument.EntityId), + }; + + public CommandEntityIdDocumentReader() : base(_propertyNames) + { + } + + public async Task Read(DbDataReader dbDataReader, CancellationToken cancellationToken) + { + return new CommandDocument + { + EntityId = new Id(await dbDataReader.GetFieldValueAsync(_entityIdOrdinal)) + }; + } +} diff --git a/src/EntityDb.SqlDb/Documents/Command/CommandEntityVersionNumberDocumentReader.cs b/src/EntityDb.SqlDb/Documents/Command/CommandEntityVersionNumberDocumentReader.cs new file mode 100644 index 00000000..64052723 --- /dev/null +++ b/src/EntityDb.SqlDb/Documents/Command/CommandEntityVersionNumberDocumentReader.cs @@ -0,0 +1,24 @@ +using EntityDb.Abstractions.ValueObjects; +using System.Data.Common; + +namespace EntityDb.SqlDb.Documents.Command; + +internal class CommandEntityVersionNumberDocumentReader : CommandDocumentReaderBase, IDocumentReader +{ + private static readonly string[] _propertyNames = + { + nameof(CommandDocument.EntityVersionNumber), + }; + + public CommandEntityVersionNumberDocumentReader() : base(_propertyNames) + { + } + + public async Task Read(DbDataReader dbDataReader, CancellationToken cancellationToken) + { + return new CommandDocument + { + EntityVersionNumber = new VersionNumber(Convert.ToUInt64(await dbDataReader.GetFieldValueAsync(_entityVersionNumberOrdinal))) + }; + } +} diff --git a/src/EntityDb.SqlDb/Documents/Command/CommandTransactionIdDocumentReader.cs b/src/EntityDb.SqlDb/Documents/Command/CommandTransactionIdDocumentReader.cs new file mode 100644 index 00000000..c7bf96f3 --- /dev/null +++ b/src/EntityDb.SqlDb/Documents/Command/CommandTransactionIdDocumentReader.cs @@ -0,0 +1,24 @@ +using EntityDb.Abstractions.ValueObjects; +using System.Data.Common; + +namespace EntityDb.SqlDb.Documents.Command; + +internal class CommandTransactionIdDocumentReader : CommandDocumentReaderBase, IDocumentReader +{ + private static readonly string[] _propertyNames = + { + nameof(CommandDocument.TransactionId), + }; + + public CommandTransactionIdDocumentReader() : base(_propertyNames) + { + } + + public async Task Read(DbDataReader dbDataReader, CancellationToken cancellationToken) + { + return new CommandDocument + { + TransactionId = new Id(await dbDataReader.GetFieldValueAsync(_transactionIdOrdinal)) + }; + } +} diff --git a/src/EntityDb.SqlDb/Documents/DocumentBase.cs b/src/EntityDb.SqlDb/Documents/DocumentBase.cs new file mode 100644 index 00000000..81202498 --- /dev/null +++ b/src/EntityDb.SqlDb/Documents/DocumentBase.cs @@ -0,0 +1,12 @@ +using EntityDb.Abstractions.ValueObjects; + +namespace EntityDb.SqlDb.Documents; + +internal abstract record DocumentBase +{ + public Guid? Id { get; init; } + public TimeStamp TransactionTimeStamp { get; init; } + public Id TransactionId { get; init; } + public string DataType { get; init; } = default!; + public string Data { get; init; } = default!; +} diff --git a/src/EntityDb.SqlDb/Documents/IDocumentReader.cs b/src/EntityDb.SqlDb/Documents/IDocumentReader.cs new file mode 100644 index 00000000..73045465 --- /dev/null +++ b/src/EntityDb.SqlDb/Documents/IDocumentReader.cs @@ -0,0 +1,13 @@ +using System.Data.Common; + +namespace EntityDb.SqlDb.Documents; + +internal interface IDocumentReader +{ + string[] GetPropertyNames(); +} + +internal interface IDocumentReader : IDocumentReader +{ + Task Read(DbDataReader dbDataReader, CancellationToken cancellationToken); +} diff --git a/src/EntityDb.SqlDb/Documents/IEntitiesDocument.cs b/src/EntityDb.SqlDb/Documents/IEntitiesDocument.cs new file mode 100644 index 00000000..f918b821 --- /dev/null +++ b/src/EntityDb.SqlDb/Documents/IEntitiesDocument.cs @@ -0,0 +1,11 @@ +namespace EntityDb.SqlDb.Documents; + +internal interface IEntitiesDocument : Common.Documents.IEntitiesDocument, ITransactionDocument +{ +} + +internal interface IEntitiesDocument : IEntitiesDocument, ITransactionDocument + where TDocument : IEntitiesDocument +{ + static abstract IDocumentReader EntityIdsDocumentReader { get; } +} diff --git a/src/EntityDb.SqlDb/Documents/IEntityDocument.cs b/src/EntityDb.SqlDb/Documents/IEntityDocument.cs new file mode 100644 index 00000000..819edd2a --- /dev/null +++ b/src/EntityDb.SqlDb/Documents/IEntityDocument.cs @@ -0,0 +1,11 @@ +namespace EntityDb.SqlDb.Documents; + +internal interface IEntityDocument : Common.Documents.IEntityDocument, ITransactionDocument +{ +} + +internal interface IEntityDocument : IEntityDocument, ITransactionDocument + where TDocument : IEntityDocument +{ + static abstract IDocumentReader EntityIdDocumentReader { get; } +} diff --git a/src/EntityDb.SqlDb/Documents/ITransactionDocument.cs b/src/EntityDb.SqlDb/Documents/ITransactionDocument.cs new file mode 100644 index 00000000..99ddc5e7 --- /dev/null +++ b/src/EntityDb.SqlDb/Documents/ITransactionDocument.cs @@ -0,0 +1,18 @@ +namespace EntityDb.SqlDb.Documents; + +internal interface ITransactionDocument : Common.Documents.ITransactionDocument +{ + static abstract string TableName { get; } + + Guid? Id { get; } + + Dictionary ToDictionary(); +} + +internal interface ITransactionDocument : ITransactionDocument + where TDocument : ITransactionDocument +{ + static abstract IDocumentReader DocumentReader { get; } + static abstract IDocumentReader TransactionIdDocumentReader { get; } + static abstract IDocumentReader DataDocumentReader { get; } +} diff --git a/src/EntityDb.SqlDb/Documents/Lease/LeaseDataDocumentReader.cs b/src/EntityDb.SqlDb/Documents/Lease/LeaseDataDocumentReader.cs new file mode 100644 index 00000000..8d246d03 --- /dev/null +++ b/src/EntityDb.SqlDb/Documents/Lease/LeaseDataDocumentReader.cs @@ -0,0 +1,23 @@ +using System.Data.Common; + +namespace EntityDb.SqlDb.Documents.Lease; + +internal class LeaseDataDocumentReader : LeaseDocumentReaderBase, IDocumentReader +{ + private static readonly string[] _propertyNames = + { + nameof(LeaseDocument.Data), + }; + + public LeaseDataDocumentReader() : base(_propertyNames) + { + } + + public async Task Read(DbDataReader dbDataReader, CancellationToken cancellationToken) + { + return new LeaseDocument + { + Data = await dbDataReader.GetFieldValueAsync(_dataOrdinal) + }; + } +} diff --git a/src/EntityDb.SqlDb/Documents/Lease/LeaseDocument.cs b/src/EntityDb.SqlDb/Documents/Lease/LeaseDocument.cs new file mode 100644 index 00000000..d6135e94 --- /dev/null +++ b/src/EntityDb.SqlDb/Documents/Lease/LeaseDocument.cs @@ -0,0 +1,111 @@ +using EntityDb.Abstractions.Queries; +using EntityDb.Abstractions.Transactions; +using EntityDb.Abstractions.Transactions.Steps; +using EntityDb.Abstractions.ValueObjects; +using EntityDb.Common.Envelopes; +using EntityDb.Common.Queries; +using EntityDb.SqlDb.Commands; +using EntityDb.SqlDb.Queries; +using EntityDb.SqlDb.Queries.FilterBuilders; +using EntityDb.SqlDb.Queries.SortBuilders; + +namespace EntityDb.SqlDb.Documents.Lease; + +internal sealed record LeaseDocument : DocumentBase, IEntityDocument +{ + public static string TableName => "Leases"; + + private static readonly LeaseFilterBuilder FilterBuilder = new(); + + private static readonly LeaseSortBuilder SortBuilder = new(); + + public string Scope { get; init; } = default!; + public string Label { get; init; } = default!; + public string Value { get; init; } = default!; + public Id EntityId { get; init; } + public VersionNumber EntityVersionNumber { get; init; } + + public static IDocumentReader DocumentReader { get; } = new LeaseDocumentReader(); + + public static IDocumentReader TransactionIdDocumentReader { get; } = new LeaseTransactionIdDocumentReader(); + + public static IDocumentReader DataDocumentReader { get; } = new LeaseDataDocumentReader(); + + public static IDocumentReader EntityIdDocumentReader { get; } = new LeaseEntityIdDocumentReader(); + + public static InsertDocumentsCommand GetInsert + ( + IEnvelopeService envelopeService, + ITransaction transaction, + IAddLeasesTransactionStep addLeasesTransactionStep + ) + { + return new InsertDocumentsCommand + ( + TableName, + addLeasesTransactionStep.Leases + .Select(insertLease => + { + return new LeaseDocument + { + TransactionTimeStamp = transaction.TimeStamp, + TransactionId = transaction.Id, + EntityId = addLeasesTransactionStep.EntityId, + EntityVersionNumber = addLeasesTransactionStep.EntityVersionNumber, + Scope = insertLease.Scope, + Label = insertLease.Label, + Value = insertLease.Value, + DataType = insertLease.GetType().Name, + Data = envelopeService.Serialize(insertLease) + }; + }) + .ToArray() + ); + } + + public static DocumentQuery GetQuery + ( + ILeaseQuery leaseQuery + ) + { + return new DocumentQuery + ( + leaseQuery.GetFilter(FilterBuilder), + leaseQuery.GetSort(SortBuilder), + leaseQuery.Skip, + leaseQuery.Take, + leaseQuery.Options + ); + } + + public static DeleteDocumentsCommand GetDeleteCommand + ( + IDeleteLeasesTransactionStep deleteLeasesTransactionStep + ) + { + var deleteLeasesQuery = + new DeleteLeasesQuery(deleteLeasesTransactionStep.EntityId, deleteLeasesTransactionStep.Leases); + + return new DeleteDocumentsCommand + ( + TableName, + deleteLeasesQuery.GetFilter(FilterBuilder) + ); + } + + public Dictionary ToDictionary() + { + return new Dictionary + { + [nameof(TransactionId)] = TransactionId, + [nameof(TransactionTimeStamp)] = TransactionTimeStamp, + [nameof(EntityId)] = EntityId, + [nameof(EntityVersionNumber)] = EntityVersionNumber, + [nameof(DataType)] = DataType, + [nameof(Data)] = Data, + [nameof(Scope)] = Scope, + [nameof(Label)] = Label, + [nameof(Value)] = Value, + }; + } +} diff --git a/src/EntityDb.SqlDb/Documents/Lease/LeaseDocumentReader.cs b/src/EntityDb.SqlDb/Documents/Lease/LeaseDocumentReader.cs new file mode 100644 index 00000000..08b248b1 --- /dev/null +++ b/src/EntityDb.SqlDb/Documents/Lease/LeaseDocumentReader.cs @@ -0,0 +1,40 @@ +using EntityDb.Abstractions.ValueObjects; +using System.Data.Common; + +namespace EntityDb.SqlDb.Documents.Lease; + +internal class LeaseDocumentReader : LeaseDocumentReaderBase, IDocumentReader +{ + private static readonly string[] _propertyNames = + { + nameof(LeaseDocument.TransactionId), + nameof(LeaseDocument.TransactionTimeStamp), + nameof(LeaseDocument.EntityId), + nameof(LeaseDocument.EntityVersionNumber), + nameof(LeaseDocument.DataType), + nameof(LeaseDocument.Data), + nameof(LeaseDocument.Scope), + nameof(LeaseDocument.Label), + nameof(LeaseDocument.Value), + }; + + public LeaseDocumentReader() : base(_propertyNames) + { + } + + public async Task Read(DbDataReader dbDataReader, CancellationToken cancellationToken) + { + return new LeaseDocument + { + TransactionId = new Id(await dbDataReader.GetFieldValueAsync(_transactionIdOrdinal)), + TransactionTimeStamp = new TimeStamp(await dbDataReader.GetFieldValueAsync(_transactionTimeStampOrdinal)), + EntityId = new Id(await dbDataReader.GetFieldValueAsync(_entityIdOrdinal)), + EntityVersionNumber = new VersionNumber(Convert.ToUInt64(await dbDataReader.GetFieldValueAsync(_entityVersionNumberOrdinal))), + DataType = await dbDataReader.GetFieldValueAsync(_dataTypeOrdinal), + Data = await dbDataReader.GetFieldValueAsync(_dataOrdinal), + Scope = await dbDataReader.GetFieldValueAsync(_scopeOrdinal), + Label = await dbDataReader.GetFieldValueAsync(_labelOrdinal), + Value = await dbDataReader.GetFieldValueAsync(_valueOrdinal), + }; + } +} diff --git a/src/EntityDb.SqlDb/Documents/Lease/LeaseDocumentReaderBase.cs b/src/EntityDb.SqlDb/Documents/Lease/LeaseDocumentReaderBase.cs new file mode 100644 index 00000000..6184cd1e --- /dev/null +++ b/src/EntityDb.SqlDb/Documents/Lease/LeaseDocumentReaderBase.cs @@ -0,0 +1,33 @@ +namespace EntityDb.SqlDb.Documents.Lease; + +internal abstract class LeaseDocumentReaderBase +{ + private readonly string[] _propertyNames; + + protected readonly int _transactionIdOrdinal; + protected readonly int _transactionTimeStampOrdinal; + protected readonly int _entityIdOrdinal; + protected readonly int _entityVersionNumberOrdinal; + protected readonly int _dataTypeOrdinal; + protected readonly int _dataOrdinal; + protected readonly int _scopeOrdinal; + protected readonly int _labelOrdinal; + protected readonly int _valueOrdinal; + + public string[] GetPropertyNames() => _propertyNames; + + protected LeaseDocumentReaderBase(string[] propertyNames) + { + _propertyNames = propertyNames; + + _transactionIdOrdinal = Array.IndexOf(_propertyNames, nameof(LeaseDocument.TransactionId)); + _transactionTimeStampOrdinal = Array.IndexOf(_propertyNames, nameof(LeaseDocument.TransactionTimeStamp)); + _entityIdOrdinal = Array.IndexOf(_propertyNames, nameof(LeaseDocument.EntityId)); + _entityVersionNumberOrdinal = Array.IndexOf(_propertyNames, nameof(LeaseDocument.EntityVersionNumber)); + _dataTypeOrdinal = Array.IndexOf(_propertyNames, nameof(LeaseDocument.DataType)); + _dataOrdinal = Array.IndexOf(_propertyNames, nameof(LeaseDocument.Data)); + _scopeOrdinal = Array.IndexOf(_propertyNames, nameof(LeaseDocument.Scope)); + _labelOrdinal = Array.IndexOf(_propertyNames, nameof(LeaseDocument.Label)); + _valueOrdinal = Array.IndexOf(_propertyNames, nameof(LeaseDocument.Value)); + } +} diff --git a/src/EntityDb.SqlDb/Documents/Lease/LeaseEntityIdDocumentReader.cs b/src/EntityDb.SqlDb/Documents/Lease/LeaseEntityIdDocumentReader.cs new file mode 100644 index 00000000..2a20b391 --- /dev/null +++ b/src/EntityDb.SqlDb/Documents/Lease/LeaseEntityIdDocumentReader.cs @@ -0,0 +1,24 @@ +using EntityDb.Abstractions.ValueObjects; +using System.Data.Common; + +namespace EntityDb.SqlDb.Documents.Lease; + +internal class LeaseEntityIdDocumentReader : LeaseDocumentReaderBase, IDocumentReader +{ + private static readonly string[] _propertyName = + { + nameof(LeaseDocument.EntityId), + }; + + public LeaseEntityIdDocumentReader() : base(_propertyName) + { + } + + public async Task Read(DbDataReader dbDataReader, CancellationToken cancellationToken) + { + return new LeaseDocument + { + EntityId = new Id(await dbDataReader.GetFieldValueAsync(_entityIdOrdinal)) + }; + } +} diff --git a/src/EntityDb.SqlDb/Documents/Lease/LeaseTransactionIdDocumentReader.cs b/src/EntityDb.SqlDb/Documents/Lease/LeaseTransactionIdDocumentReader.cs new file mode 100644 index 00000000..3aef3b6d --- /dev/null +++ b/src/EntityDb.SqlDb/Documents/Lease/LeaseTransactionIdDocumentReader.cs @@ -0,0 +1,24 @@ +using EntityDb.Abstractions.ValueObjects; +using System.Data.Common; + +namespace EntityDb.SqlDb.Documents.Lease; + +internal class LeaseTransactionIdDocumentReader : LeaseDocumentReaderBase, IDocumentReader +{ + private static readonly string[] _propertyNames = + { + nameof(LeaseDocument.TransactionId), + }; + + public LeaseTransactionIdDocumentReader() : base(_propertyNames) + { + } + + public async Task Read(DbDataReader dbDataReader, CancellationToken cancellationToken) + { + return new LeaseDocument + { + TransactionId = new Id(await dbDataReader.GetFieldValueAsync(_transactionIdOrdinal)) + }; + } +} diff --git a/src/EntityDb.SqlDb/Documents/Tag/TagDataDocumentReader.cs b/src/EntityDb.SqlDb/Documents/Tag/TagDataDocumentReader.cs new file mode 100644 index 00000000..595c790b --- /dev/null +++ b/src/EntityDb.SqlDb/Documents/Tag/TagDataDocumentReader.cs @@ -0,0 +1,23 @@ +using System.Data.Common; + +namespace EntityDb.SqlDb.Documents.Tag; + +internal class TagDataDocumentReader : TagDocumentReaderBase, IDocumentReader +{ + private static readonly string[] _propertyNames = + { + nameof(TagDocument.Data), + }; + + public TagDataDocumentReader() : base(_propertyNames) + { + } + + public async Task Read(DbDataReader dbDataReader, CancellationToken cancellationToken) + { + return new TagDocument + { + Data = await dbDataReader.GetFieldValueAsync(_dataOrdinal) + }; + } +} diff --git a/src/EntityDb.SqlDb/Documents/Tag/TagDocument.cs b/src/EntityDb.SqlDb/Documents/Tag/TagDocument.cs new file mode 100644 index 00000000..9ca3baa2 --- /dev/null +++ b/src/EntityDb.SqlDb/Documents/Tag/TagDocument.cs @@ -0,0 +1,107 @@ +using EntityDb.Abstractions.Queries; +using EntityDb.Abstractions.Transactions; +using EntityDb.Abstractions.Transactions.Steps; +using EntityDb.Abstractions.ValueObjects; +using EntityDb.Common.Envelopes; +using EntityDb.Common.Queries; +using EntityDb.SqlDb.Commands; +using EntityDb.SqlDb.Queries; +using EntityDb.SqlDb.Queries.FilterBuilders; +using EntityDb.SqlDb.Queries.SortBuilders; + +namespace EntityDb.SqlDb.Documents.Tag; + +internal sealed record TagDocument : DocumentBase, IEntityDocument +{ + public static string TableName => "Tags"; + + private static readonly TagFilterBuilder FilterBuilder = new(); + + private static readonly TagSortBuilder SortBuilder = new(); + + public string Label { get; init; } = default!; + public string Value { get; init; } = default!; + public Id EntityId { get; init; } + public VersionNumber EntityVersionNumber { get; init; } + + public static IDocumentReader DocumentReader { get; } = new TagDocumentReader(); + + public static IDocumentReader TransactionIdDocumentReader { get; } = new TagTransactionIdDocumentReader(); + + public static IDocumentReader DataDocumentReader { get; } = new TagDataDocumentReader(); + + public static IDocumentReader EntityIdDocumentReader { get; } = new TagEntityIdDocumentReader(); + + public static InsertDocumentsCommand GetInsert + ( + IEnvelopeService envelopeService, + ITransaction transaction, + IAddTagsTransactionStep addTagsTransactionStep + ) + { + return new InsertDocumentsCommand + ( + TableName, + addTagsTransactionStep.Tags + .Select(insertTag => + { + return new TagDocument + { + TransactionTimeStamp = transaction.TimeStamp, + TransactionId = transaction.Id, + EntityId = addTagsTransactionStep.EntityId, + EntityVersionNumber = addTagsTransactionStep.EntityVersionNumber, + Label = insertTag.Label, + Value = insertTag.Value, + DataType = insertTag.GetType().Name, + Data = envelopeService.Serialize(insertTag) + }; + }) + .ToArray() + ); + } + + public static DocumentQuery GetQuery + ( + ITagQuery tagQuery + ) + { + return new DocumentQuery + ( + tagQuery.GetFilter(FilterBuilder), + tagQuery.GetSort(SortBuilder), + tagQuery.Skip, + tagQuery.Take, + tagQuery.Options + ); + } + + public static DeleteDocumentsCommand GetDeleteCommand + ( + IDeleteTagsTransactionStep deleteTagsTransactionStep + ) + { + var deleteTagsQuery = new DeleteTagsQuery(deleteTagsTransactionStep.EntityId, deleteTagsTransactionStep.Tags); + + return new DeleteDocumentsCommand + ( + TableName, + deleteTagsQuery.GetFilter(FilterBuilder) + ); + } + + public Dictionary ToDictionary() + { + return new Dictionary + { + [nameof(TransactionId)] = TransactionId, + [nameof(TransactionTimeStamp)] = TransactionTimeStamp, + [nameof(EntityId)] = EntityId, + [nameof(EntityVersionNumber)] = EntityVersionNumber, + [nameof(DataType)] = DataType, + [nameof(Data)] = Data, + [nameof(Label)] = Label, + [nameof(Value)] = Value, + }; + } +} diff --git a/src/EntityDb.SqlDb/Documents/Tag/TagDocumentReader.cs b/src/EntityDb.SqlDb/Documents/Tag/TagDocumentReader.cs new file mode 100644 index 00000000..c3b88336 --- /dev/null +++ b/src/EntityDb.SqlDb/Documents/Tag/TagDocumentReader.cs @@ -0,0 +1,38 @@ +using EntityDb.Abstractions.ValueObjects; +using System.Data.Common; + +namespace EntityDb.SqlDb.Documents.Tag; + +internal class TagDocumentReader : TagDocumentReaderBase, IDocumentReader +{ + private static readonly string[] _propertyNames = + { + nameof(TagDocument.TransactionId), + nameof(TagDocument.TransactionTimeStamp), + nameof(TagDocument.EntityId), + nameof(TagDocument.EntityVersionNumber), + nameof(TagDocument.DataType), + nameof(TagDocument.Data), + nameof(TagDocument.Label), + nameof(TagDocument.Value), + }; + + public TagDocumentReader() : base(_propertyNames) + { + } + + public async Task Read(DbDataReader dbDataReader, CancellationToken cancellationToken) + { + return new TagDocument + { + TransactionId = new Id(await dbDataReader.GetFieldValueAsync(_transactionIdOrdinal)), + TransactionTimeStamp = new TimeStamp(await dbDataReader.GetFieldValueAsync(_transactionTimeStampOrdinal)), + EntityId = new Id(await dbDataReader.GetFieldValueAsync(_entityIdOrdinal)), + EntityVersionNumber = new VersionNumber(Convert.ToUInt64(await dbDataReader.GetFieldValueAsync(_entityVersionNumberOrdinal))), + DataType = await dbDataReader.GetFieldValueAsync(_dataTypeOrdinal), + Data = await dbDataReader.GetFieldValueAsync(_dataOrdinal), + Label = await dbDataReader.GetFieldValueAsync(_labelOrdinal), + Value = await dbDataReader.GetFieldValueAsync(_valueOrdinal), + }; + } +} diff --git a/src/EntityDb.SqlDb/Documents/Tag/TagDocumentReaderBase.cs b/src/EntityDb.SqlDb/Documents/Tag/TagDocumentReaderBase.cs new file mode 100644 index 00000000..af3ec606 --- /dev/null +++ b/src/EntityDb.SqlDb/Documents/Tag/TagDocumentReaderBase.cs @@ -0,0 +1,31 @@ +namespace EntityDb.SqlDb.Documents.Tag; + +internal abstract class TagDocumentReaderBase +{ + private readonly string[] _propertyNames; + + protected readonly int _transactionIdOrdinal; + protected readonly int _transactionTimeStampOrdinal; + protected readonly int _entityIdOrdinal; + protected readonly int _entityVersionNumberOrdinal; + protected readonly int _dataTypeOrdinal; + protected readonly int _dataOrdinal; + protected readonly int _labelOrdinal; + protected readonly int _valueOrdinal; + + public string[] GetPropertyNames() => _propertyNames; + + protected TagDocumentReaderBase(string[] propertyNames) + { + _propertyNames = propertyNames; + + _transactionIdOrdinal = Array.IndexOf(_propertyNames, nameof(TagDocument.TransactionId)); + _transactionTimeStampOrdinal = Array.IndexOf(_propertyNames, nameof(TagDocument.TransactionTimeStamp)); + _entityIdOrdinal = Array.IndexOf(_propertyNames, nameof(TagDocument.EntityId)); + _entityVersionNumberOrdinal = Array.IndexOf(_propertyNames, nameof(TagDocument.EntityVersionNumber)); + _dataTypeOrdinal = Array.IndexOf(_propertyNames, nameof(TagDocument.DataType)); + _dataOrdinal = Array.IndexOf(_propertyNames, nameof(TagDocument.Data)); + _labelOrdinal = Array.IndexOf(_propertyNames, nameof(TagDocument.Label)); + _valueOrdinal = Array.IndexOf(_propertyNames, nameof(TagDocument.Value)); + } +} diff --git a/src/EntityDb.SqlDb/Documents/Tag/TagEntityIdDocumentReader.cs b/src/EntityDb.SqlDb/Documents/Tag/TagEntityIdDocumentReader.cs new file mode 100644 index 00000000..d31e85cd --- /dev/null +++ b/src/EntityDb.SqlDb/Documents/Tag/TagEntityIdDocumentReader.cs @@ -0,0 +1,24 @@ +using EntityDb.Abstractions.ValueObjects; +using System.Data.Common; + +namespace EntityDb.SqlDb.Documents.Tag; + +internal class TagEntityIdDocumentReader : TagDocumentReaderBase, IDocumentReader +{ + private static readonly string[] _propertyNames = + { + nameof(TagDocument.EntityId), + }; + + public TagEntityIdDocumentReader() : base(_propertyNames) + { + } + + public async Task Read(DbDataReader dbDataReader, CancellationToken cancellationToken) + { + return new TagDocument + { + EntityId = new Id(await dbDataReader.GetFieldValueAsync(_entityIdOrdinal)) + }; + } +} diff --git a/src/EntityDb.SqlDb/Documents/Tag/TagTransactionIdDocumentReader.cs b/src/EntityDb.SqlDb/Documents/Tag/TagTransactionIdDocumentReader.cs new file mode 100644 index 00000000..5a394a9c --- /dev/null +++ b/src/EntityDb.SqlDb/Documents/Tag/TagTransactionIdDocumentReader.cs @@ -0,0 +1,24 @@ +using EntityDb.Abstractions.ValueObjects; +using System.Data.Common; + +namespace EntityDb.SqlDb.Documents.Tag; + +internal class TagTransactionIdDocumentReader : TagDocumentReaderBase, IDocumentReader +{ + private static readonly string[] _propertyNames = + { + nameof(TagDocument.TransactionId), + }; + + public TagTransactionIdDocumentReader() : base(_propertyNames) + { + } + + public async Task Read(DbDataReader dbDataReader, CancellationToken cancellationToken) + { + return new TagDocument + { + TransactionId = new Id(await dbDataReader.GetFieldValueAsync(_transactionIdOrdinal)) + }; + } +} diff --git a/src/EntityDb.SqlDb/EntityDb.SqlDb.csproj b/src/EntityDb.SqlDb/EntityDb.SqlDb.csproj new file mode 100644 index 00000000..eb6e3a1a --- /dev/null +++ b/src/EntityDb.SqlDb/EntityDb.SqlDb.csproj @@ -0,0 +1,12 @@ + + + + false + + + + + + + + diff --git a/src/EntityDb.SqlDb/Extensions/DocumentQueryExtensions.cs b/src/EntityDb.SqlDb/Extensions/DocumentQueryExtensions.cs new file mode 100644 index 00000000..86b9968b --- /dev/null +++ b/src/EntityDb.SqlDb/Extensions/DocumentQueryExtensions.cs @@ -0,0 +1,155 @@ +using EntityDb.Abstractions.Annotations; +using EntityDb.Abstractions.ValueObjects; +using EntityDb.Common.Envelopes; +using EntityDb.Common.Extensions; +using EntityDb.Common.Polyfills; +using EntityDb.SqlDb.Documents; +using EntityDb.SqlDb.Queries; +using EntityDb.SqlDb.Sessions; +using System.Runtime.CompilerServices; + +namespace EntityDb.SqlDb.Extensions; + +internal static class DocumentQueryExtensions +{ + + private static IAsyncEnumerable EnumerateIds + ( + this DocumentQuery documentQuery, + ISqlDbSession sqlDbSession, + IDocumentReader documentReader, + Func, IAsyncEnumerable> mapToIds, + CancellationToken cancellationToken + ) + where TDocument : ITransactionDocument + where TOptions : class + { + var skip = documentQuery.Skip; + var limit = documentQuery.Limit; + + documentQuery = documentQuery with { Skip = null, Limit = null }; + + var documents = documentQuery.Execute(sqlDbSession, documentReader, cancellationToken); + + return documents.EnumerateIds(skip, limit, mapToIds); + } + + public static IAsyncEnumerable EnumerateTransactionIds + ( + this DocumentQuery documentQuery, + ISqlDbSession sqlDbSession, + CancellationToken cancellationToken + ) + where TOptions : class + where TDocument : ITransactionDocument + { + return documentQuery.EnumerateIds + ( + sqlDbSession, + TDocument.TransactionIdDocumentReader, + documents => documents.Select(document => document.TransactionId), + cancellationToken + ); + } + + public static IAsyncEnumerable EnumerateEntityIds + ( + this DocumentQuery documentQuery, + ISqlDbSession sqlDbSession, + CancellationToken cancellationToken + ) + where TOptions : class + where TDocument : IEntityDocument + { + return documentQuery.EnumerateIds + ( + sqlDbSession, + TDocument.EntityIdDocumentReader, + documents => documents.Select(document => document.EntityId), + cancellationToken + ); + } + + public static IAsyncEnumerable EnumerateEntitiesIds + ( + this DocumentQuery documentQuery, + ISqlDbSession sqlDbSession, + CancellationToken cancellationToken + ) + where TOptions : class + where TDocument : IEntitiesDocument + { + return documentQuery.EnumerateIds + ( + sqlDbSession, + TDocument.EntityIdsDocumentReader, + documents => documents.SelectMany(document => AsyncEnumerablePolyfill.FromResult(document.EntityIds)), + cancellationToken + ); + } + + public static async IAsyncEnumerable EnumerateData + ( + this DocumentQuery documentQuery, + ISqlDbSession sqlDbSession, + IEnvelopeService envelopeService, + [EnumeratorCancellation] CancellationToken cancellationToken + ) + where TOptions : class + where TDocument : ITransactionDocument + { + var documents = documentQuery.Execute + ( + sqlDbSession, + TDocument.DataDocumentReader, + cancellationToken + ); + + await foreach (var document in documents) + { + yield return envelopeService.Deserialize(document.Data); + } + } + + public static IAsyncEnumerable> EnumerateEntityAnnotation + ( + this DocumentQuery documentQuery, + ISqlDbSession sqlDbSession, + IEnvelopeService envelopeService, + CancellationToken cancellationToken + ) + where TOptions : class + where TDocument : IEntityDocument + where TData : notnull + { + var documents = documentQuery.Execute + ( + sqlDbSession, + TDocument.DocumentReader, + cancellationToken + ); + + return documents.EnumerateEntityAnnotation(envelopeService, cancellationToken); + } + + public static IAsyncEnumerable> EnumerateEntitiesAnnotation + ( + this DocumentQuery documentQuery, + ISqlDbSession sqlDbSession, + IEnvelopeService envelopeService, + CancellationToken cancellationToken + ) + where TOptions : class + where TDocument : IEntitiesDocument + where TData : notnull + { + var documents = documentQuery.Execute + ( + sqlDbSession, + TDocument.DocumentReader, + cancellationToken + ); + + return documents.EnumerateEntitiesAnnotation(envelopeService, cancellationToken); + } +} diff --git a/src/EntityDb.SqlDb/Extensions/SqlDbTransactionRepositoryFactoryExtensions.cs b/src/EntityDb.SqlDb/Extensions/SqlDbTransactionRepositoryFactoryExtensions.cs new file mode 100644 index 00000000..252d1c7a --- /dev/null +++ b/src/EntityDb.SqlDb/Extensions/SqlDbTransactionRepositoryFactoryExtensions.cs @@ -0,0 +1,18 @@ +using EntityDb.SqlDb.Transactions; +using System.Diagnostics.CodeAnalysis; + +namespace EntityDb.SqlDb.Extensions; + +internal static class SqlDbTransactionRepositoryFactoryExtensions +{ + [ExcludeFromCodeCoverage(Justification = "Tests are only meant to run in test mode.")] + public static ISqlDbTransactionRepositoryFactory UseTestMode( + this ISqlDbTransactionRepositoryFactory mongoDbTransactionRepositoryFactory, + bool testMode) + where TOptions : class + { + return testMode + ? new TestModeSqlDbTransactionRepositoryFactory(mongoDbTransactionRepositoryFactory) + : mongoDbTransactionRepositoryFactory; + } +} diff --git a/src/EntityDb.SqlDb/Properties/AssemblyInfo.cs b/src/EntityDb.SqlDb/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..c4de5c44 --- /dev/null +++ b/src/EntityDb.SqlDb/Properties/AssemblyInfo.cs @@ -0,0 +1,7 @@ +using System.Runtime.CompilerServices; + +// src +[assembly: InternalsVisibleTo("EntityDb.Npgsql")] +[assembly: InternalsVisibleTo("EntityDb.Npgsql.Provisioner")] + +// test diff --git a/src/EntityDb.SqlDb/Queries/Definitions/Filter/AndFilterDefinition.cs b/src/EntityDb.SqlDb/Queries/Definitions/Filter/AndFilterDefinition.cs new file mode 100644 index 00000000..e22d19b5 --- /dev/null +++ b/src/EntityDb.SqlDb/Queries/Definitions/Filter/AndFilterDefinition.cs @@ -0,0 +1,3 @@ +namespace EntityDb.SqlDb.Queries.Definitions.Filter; + +internal record struct AndFilterDefinition(IFilterDefinition[] FilterDefinitions) : IFilterDefinition; diff --git a/src/EntityDb.SqlDb/Queries/Definitions/Filter/AnyInFilterDefinition.cs b/src/EntityDb.SqlDb/Queries/Definitions/Filter/AnyInFilterDefinition.cs new file mode 100644 index 00000000..36469558 --- /dev/null +++ b/src/EntityDb.SqlDb/Queries/Definitions/Filter/AnyInFilterDefinition.cs @@ -0,0 +1,5 @@ +using System.Collections; + +namespace EntityDb.SqlDb.Queries.Definitions.Filter; + +internal record struct AnyInFilterDefinition(string PropertyName, IEnumerable PropertyValues) : IFilterDefinition; diff --git a/src/EntityDb.SqlDb/Queries/Definitions/Filter/EqFilterDefinition.cs b/src/EntityDb.SqlDb/Queries/Definitions/Filter/EqFilterDefinition.cs new file mode 100644 index 00000000..60d887e5 --- /dev/null +++ b/src/EntityDb.SqlDb/Queries/Definitions/Filter/EqFilterDefinition.cs @@ -0,0 +1,3 @@ +namespace EntityDb.SqlDb.Queries.Definitions.Filter; + +internal record struct EqFilterDefinition(string PropertyName, object PropertyValue) : IFilterDefinition; diff --git a/src/EntityDb.SqlDb/Queries/Definitions/Filter/GteFilterDefinition.cs b/src/EntityDb.SqlDb/Queries/Definitions/Filter/GteFilterDefinition.cs new file mode 100644 index 00000000..9b196c86 --- /dev/null +++ b/src/EntityDb.SqlDb/Queries/Definitions/Filter/GteFilterDefinition.cs @@ -0,0 +1,3 @@ +namespace EntityDb.SqlDb.Queries.Definitions.Filter; + +internal record struct GteFilterDefinition(string PropertyName, object PropertyValue) : IFilterDefinition; diff --git a/src/EntityDb.SqlDb/Queries/Definitions/Filter/IFilterDefinition.cs b/src/EntityDb.SqlDb/Queries/Definitions/Filter/IFilterDefinition.cs new file mode 100644 index 00000000..ac5a461c --- /dev/null +++ b/src/EntityDb.SqlDb/Queries/Definitions/Filter/IFilterDefinition.cs @@ -0,0 +1,3 @@ +namespace EntityDb.SqlDb.Queries.Definitions.Filter; + +internal interface IFilterDefinition { } diff --git a/src/EntityDb.SqlDb/Queries/Definitions/Filter/InFilterDefinition.cs b/src/EntityDb.SqlDb/Queries/Definitions/Filter/InFilterDefinition.cs new file mode 100644 index 00000000..223da436 --- /dev/null +++ b/src/EntityDb.SqlDb/Queries/Definitions/Filter/InFilterDefinition.cs @@ -0,0 +1,5 @@ +using System.Collections; + +namespace EntityDb.SqlDb.Queries.Definitions.Filter; + +internal record struct InFilterDefinition(string PropertyName, IEnumerable PropertyValues) : IFilterDefinition; diff --git a/src/EntityDb.SqlDb/Queries/Definitions/Filter/LteFilterDefinition.cs b/src/EntityDb.SqlDb/Queries/Definitions/Filter/LteFilterDefinition.cs new file mode 100644 index 00000000..8928b810 --- /dev/null +++ b/src/EntityDb.SqlDb/Queries/Definitions/Filter/LteFilterDefinition.cs @@ -0,0 +1,3 @@ +namespace EntityDb.SqlDb.Queries.Definitions.Filter; + +internal record struct LteFilterDefinition(string PropertyName, object PropertyValue) : IFilterDefinition; diff --git a/src/EntityDb.SqlDb/Queries/Definitions/Filter/NotFilterDefinition.cs b/src/EntityDb.SqlDb/Queries/Definitions/Filter/NotFilterDefinition.cs new file mode 100644 index 00000000..8510ce28 --- /dev/null +++ b/src/EntityDb.SqlDb/Queries/Definitions/Filter/NotFilterDefinition.cs @@ -0,0 +1,3 @@ +namespace EntityDb.SqlDb.Queries.Definitions.Filter; + +internal record struct NotFilterDefinition(IFilterDefinition FilterDefinition) : IFilterDefinition; diff --git a/src/EntityDb.SqlDb/Queries/Definitions/Filter/OrFilterDefinition.cs b/src/EntityDb.SqlDb/Queries/Definitions/Filter/OrFilterDefinition.cs new file mode 100644 index 00000000..99fb75ae --- /dev/null +++ b/src/EntityDb.SqlDb/Queries/Definitions/Filter/OrFilterDefinition.cs @@ -0,0 +1,3 @@ +namespace EntityDb.SqlDb.Queries.Definitions.Filter; + +internal record struct OrFilterDefinition(IFilterDefinition[] FilterDefinitions) : IFilterDefinition; diff --git a/src/EntityDb.SqlDb/Queries/Definitions/Sort/AscSortDefinition.cs b/src/EntityDb.SqlDb/Queries/Definitions/Sort/AscSortDefinition.cs new file mode 100644 index 00000000..9a44c317 --- /dev/null +++ b/src/EntityDb.SqlDb/Queries/Definitions/Sort/AscSortDefinition.cs @@ -0,0 +1,3 @@ +namespace EntityDb.SqlDb.Queries.Definitions.Sort; + +internal record struct AscSortDefinition(string PropertyName) : ISortDefinition; diff --git a/src/EntityDb.SqlDb/Queries/Definitions/Sort/CombineSortDefinition.cs b/src/EntityDb.SqlDb/Queries/Definitions/Sort/CombineSortDefinition.cs new file mode 100644 index 00000000..d98b606b --- /dev/null +++ b/src/EntityDb.SqlDb/Queries/Definitions/Sort/CombineSortDefinition.cs @@ -0,0 +1,3 @@ +namespace EntityDb.SqlDb.Queries.Definitions.Sort; + +internal record struct CombineSortDefinition(ISortDefinition[] SortDefinitions) : ISortDefinition; diff --git a/src/EntityDb.SqlDb/Queries/Definitions/Sort/DescSortDefinition.cs b/src/EntityDb.SqlDb/Queries/Definitions/Sort/DescSortDefinition.cs new file mode 100644 index 00000000..cb92a9bc --- /dev/null +++ b/src/EntityDb.SqlDb/Queries/Definitions/Sort/DescSortDefinition.cs @@ -0,0 +1,3 @@ +namespace EntityDb.SqlDb.Queries.Definitions.Sort; + +internal record struct DescSortDefinition(string PropertyName) : ISortDefinition; diff --git a/src/EntityDb.SqlDb/Queries/Definitions/Sort/ISortDefinition.cs b/src/EntityDb.SqlDb/Queries/Definitions/Sort/ISortDefinition.cs new file mode 100644 index 00000000..974f4d17 --- /dev/null +++ b/src/EntityDb.SqlDb/Queries/Definitions/Sort/ISortDefinition.cs @@ -0,0 +1,3 @@ +namespace EntityDb.SqlDb.Queries.Definitions.Sort; + +internal interface ISortDefinition { } diff --git a/src/EntityDb.SqlDb/Queries/DocumentQuery.cs b/src/EntityDb.SqlDb/Queries/DocumentQuery.cs new file mode 100644 index 00000000..156f60d3 --- /dev/null +++ b/src/EntityDb.SqlDb/Queries/DocumentQuery.cs @@ -0,0 +1,23 @@ +using EntityDb.SqlDb.Documents; +using EntityDb.SqlDb.Queries.Definitions.Filter; +using EntityDb.SqlDb.Queries.Definitions.Sort; +using EntityDb.SqlDb.Sessions; + +namespace EntityDb.SqlDb.Queries; + +internal record DocumentQuery +( + IFilterDefinition FilterDefinition, + ISortDefinition? SortDefinition, + int? Skip, + int? Limit, + object? Options +) + where TDocument : ITransactionDocument +{ + public IAsyncEnumerable Execute(ISqlDbSession sqlDbSession, IDocumentReader documentReader, CancellationToken cancellationToken) + where TOptions : class + { + return sqlDbSession.Find(documentReader, FilterDefinition, SortDefinition, Skip, Limit, Options as TOptions, cancellationToken); + } +} diff --git a/src/EntityDb.SqlDb/Queries/FilterBuilders/AgentSignatureFilterBuilder.cs b/src/EntityDb.SqlDb/Queries/FilterBuilders/AgentSignatureFilterBuilder.cs new file mode 100644 index 00000000..d392d611 --- /dev/null +++ b/src/EntityDb.SqlDb/Queries/FilterBuilders/AgentSignatureFilterBuilder.cs @@ -0,0 +1,19 @@ +using EntityDb.Abstractions.Queries.FilterBuilders; +using EntityDb.Abstractions.ValueObjects; +using EntityDb.SqlDb.Documents.AgentSignature; +using EntityDb.SqlDb.Queries.Definitions.Filter; + +namespace EntityDb.SqlDb.Queries.FilterBuilders; + +internal sealed class AgentSignatureFilterBuilder : FilterBuilderBase, IAgentSignatureFilterBuilder +{ + public IFilterDefinition EntityIdsIn(params Id[] entityIds) + { + return AnyIn(nameof(AgentSignatureDocument.EntityIds), entityIds); + } + + public IFilterDefinition AgentSignatureTypeIn(params Type[] agentSignatureTypes) + { + return DataTypeIn(agentSignatureTypes); + } +} diff --git a/src/EntityDb.SqlDb/Queries/FilterBuilders/CommandFilterBuilder.cs b/src/EntityDb.SqlDb/Queries/FilterBuilders/CommandFilterBuilder.cs new file mode 100644 index 00000000..edfb8c22 --- /dev/null +++ b/src/EntityDb.SqlDb/Queries/FilterBuilders/CommandFilterBuilder.cs @@ -0,0 +1,29 @@ +using EntityDb.Abstractions.Queries.FilterBuilders; +using EntityDb.Abstractions.ValueObjects; +using EntityDb.SqlDb.Documents.Command; +using EntityDb.SqlDb.Queries.Definitions.Filter; + +namespace EntityDb.SqlDb.Queries.FilterBuilders; + +internal sealed class CommandFilterBuilder : FilterBuilderBase, ICommandFilterBuilder +{ + public IFilterDefinition EntityIdIn(params Id[] entityIds) + { + return In(nameof(CommandDocument.EntityId), entityIds); + } + + public IFilterDefinition EntityVersionNumberGte(VersionNumber entityVersionNumber) + { + return Gte(nameof(CommandDocument.EntityVersionNumber), entityVersionNumber); + } + + public IFilterDefinition EntityVersionNumberLte(VersionNumber entityVersionNumber) + { + return Lte(nameof(CommandDocument.EntityVersionNumber), entityVersionNumber); + } + + public IFilterDefinition CommandTypeIn(params Type[] commandTypes) + { + return DataTypeIn(commandTypes); + } +} diff --git a/src/EntityDb.SqlDb/Queries/FilterBuilders/FilterBuilderBase.cs b/src/EntityDb.SqlDb/Queries/FilterBuilders/FilterBuilderBase.cs new file mode 100644 index 00000000..ec587dfd --- /dev/null +++ b/src/EntityDb.SqlDb/Queries/FilterBuilders/FilterBuilderBase.cs @@ -0,0 +1,77 @@ +using EntityDb.Abstractions.Queries.FilterBuilders; +using EntityDb.Abstractions.ValueObjects; +using EntityDb.Common.Envelopes; +using EntityDb.SqlDb.Documents; +using EntityDb.SqlDb.Queries.Definitions.Filter; + +namespace EntityDb.SqlDb.Queries.FilterBuilders; + +internal abstract class FilterBuilderBase : IFilterBuilder +{ + public IFilterDefinition TransactionTimeStampGte(TimeStamp timeStamp) + { + return Gte(nameof(ITransactionDocument.TransactionTimeStamp), timeStamp); + } + + public IFilterDefinition TransactionTimeStampLte(TimeStamp timeStamp) + { + return Lte(nameof(ITransactionDocument.TransactionTimeStamp), timeStamp); + } + + public IFilterDefinition TransactionIdIn(params Id[] transactionIds) + { + return In(nameof(ITransactionDocument.TransactionId), transactionIds); + } + + protected static IFilterDefinition DataTypeIn(params Type[] dataTypes) + { + var typeNames = dataTypes.GetTypeHeaderValues(); + + return In(nameof(ITransactionDocument.DataType), typeNames); + } + + public IFilterDefinition Not(IFilterDefinition filter) + { + return new NotFilterDefinition(filter); + } + + public IFilterDefinition And(params IFilterDefinition[] filters) + { + return new AndFilterDefinition(filters); + } + + public IFilterDefinition Or(params IFilterDefinition[] filters) + { + return new OrFilterDefinition(filters); + } + + protected static IFilterDefinition Eq(string fieldName, TValue value) + where TValue : notnull + { + return new EqFilterDefinition(fieldName, value); + } + + protected static IFilterDefinition In(string fieldName, IEnumerable values) + where TValue : notnull + { + return new InFilterDefinition(fieldName, values); + } + + protected static IFilterDefinition AnyIn(string fieldName, IEnumerable values) + where TValue : notnull + { + return new AnyInFilterDefinition(fieldName, values); + } + + protected static IFilterDefinition Gte(string fieldName, TValue value) + where TValue : notnull + { + return new GteFilterDefinition(fieldName, value); + } + + protected static IFilterDefinition Lte(string fieldName, TValue value) + where TValue : notnull + { + return new LteFilterDefinition(fieldName, value); + } +} diff --git a/src/EntityDb.SqlDb/Queries/FilterBuilders/LeaseFilterBuilder.cs b/src/EntityDb.SqlDb/Queries/FilterBuilders/LeaseFilterBuilder.cs new file mode 100644 index 00000000..d078b166 --- /dev/null +++ b/src/EntityDb.SqlDb/Queries/FilterBuilders/LeaseFilterBuilder.cs @@ -0,0 +1,44 @@ +using EntityDb.Abstractions.Queries.FilterBuilders; +using EntityDb.Abstractions.ValueObjects; +using EntityDb.SqlDb.Documents.Lease; +using EntityDb.SqlDb.Queries.Definitions.Filter; + +namespace EntityDb.SqlDb.Queries.FilterBuilders; + +internal sealed class LeaseFilterBuilder : FilterBuilderBase, ILeaseFilterBuilder +{ + public IFilterDefinition EntityIdIn(params Id[] entityIds) + { + return In(nameof(LeaseDocument.EntityId), entityIds); + } + + public IFilterDefinition EntityVersionNumberGte(VersionNumber entityVersionNumber) + { + return Gte(nameof(LeaseDocument.EntityVersionNumber), entityVersionNumber); + } + + public IFilterDefinition EntityVersionNumberLte(VersionNumber entityVersionNumber) + { + return Lte(nameof(LeaseDocument.EntityVersionNumber), entityVersionNumber); + } + + public IFilterDefinition LeaseTypeIn(params Type[] leaseTypes) + { + return DataTypeIn(leaseTypes); + } + + public IFilterDefinition LeaseScopeEq(string scope) + { + return Eq(nameof(LeaseDocument.Scope), scope); + } + + public IFilterDefinition LeaseLabelEq(string label) + { + return Eq(nameof(LeaseDocument.Label), label); + } + + public IFilterDefinition LeaseValueEq(string value) + { + return Eq(nameof(LeaseDocument.Value), value); + } +} diff --git a/src/EntityDb.SqlDb/Queries/FilterBuilders/TagFilterBuilder.cs b/src/EntityDb.SqlDb/Queries/FilterBuilders/TagFilterBuilder.cs new file mode 100644 index 00000000..043aa9a7 --- /dev/null +++ b/src/EntityDb.SqlDb/Queries/FilterBuilders/TagFilterBuilder.cs @@ -0,0 +1,39 @@ +using EntityDb.Abstractions.Queries.FilterBuilders; +using EntityDb.Abstractions.ValueObjects; +using EntityDb.SqlDb.Documents.Tag; +using EntityDb.SqlDb.Queries.Definitions.Filter; + +namespace EntityDb.SqlDb.Queries.FilterBuilders; + +internal sealed class TagFilterBuilder : FilterBuilderBase, ITagFilterBuilder +{ + public IFilterDefinition EntityIdIn(params Id[] entityIds) + { + return In(nameof(TagDocument.EntityId), entityIds); + } + + public IFilterDefinition EntityVersionNumberGte(VersionNumber entityVersionNumber) + { + return Gte(nameof(TagDocument.EntityVersionNumber), entityVersionNumber); + } + + public IFilterDefinition EntityVersionNumberLte(VersionNumber entityVersionNumber) + { + return Lte(nameof(TagDocument.EntityVersionNumber), entityVersionNumber); + } + + public IFilterDefinition TagTypeIn(params Type[] tagTypes) + { + return DataTypeIn(tagTypes); + } + + public IFilterDefinition TagLabelEq(string label) + { + return Eq(nameof(TagDocument.Label), label); + } + + public IFilterDefinition TagValueEq(string value) + { + return Eq(nameof(TagDocument.Value), value); + } +} diff --git a/src/EntityDb.SqlDb/Queries/SortBuilders/AgentSignatureSortBuilder.cs b/src/EntityDb.SqlDb/Queries/SortBuilders/AgentSignatureSortBuilder.cs new file mode 100644 index 00000000..561b170e --- /dev/null +++ b/src/EntityDb.SqlDb/Queries/SortBuilders/AgentSignatureSortBuilder.cs @@ -0,0 +1,18 @@ +using EntityDb.Abstractions.Queries.SortBuilders; +using EntityDb.SqlDb.Documents.AgentSignature; +using EntityDb.SqlDb.Queries.Definitions.Sort; + +namespace EntityDb.SqlDb.Queries.SortBuilders; + +internal sealed class AgentSignatureSortBuilder : SortBuilderBase, IAgentSignatureSortBuilder +{ + public ISortDefinition EntityIds(bool ascending) + { + return Sort(ascending, nameof(AgentSignatureDocument.EntityIds)); + } + + public ISortDefinition AgentSignatureType(bool ascending) + { + return Sort(ascending, nameof(AgentSignatureDocument.DataType)); + } +} diff --git a/src/EntityDb.SqlDb/Queries/SortBuilders/CommandSortBuilder.cs b/src/EntityDb.SqlDb/Queries/SortBuilders/CommandSortBuilder.cs new file mode 100644 index 00000000..762b810c --- /dev/null +++ b/src/EntityDb.SqlDb/Queries/SortBuilders/CommandSortBuilder.cs @@ -0,0 +1,23 @@ +using EntityDb.Abstractions.Queries.SortBuilders; +using EntityDb.SqlDb.Documents.Command; +using EntityDb.SqlDb.Queries.Definitions.Sort; + +namespace EntityDb.SqlDb.Queries.SortBuilders; + +internal sealed class CommandSortBuilder : SortBuilderBase, ICommandSortBuilder +{ + public ISortDefinition EntityId(bool ascending) + { + return Sort(ascending, nameof(CommandDocument.EntityId)); + } + + public ISortDefinition EntityVersionNumber(bool ascending) + { + return Sort(ascending, nameof(CommandDocument.EntityVersionNumber)); + } + + public ISortDefinition CommandType(bool ascending) + { + return SortDataType(ascending); + } +} diff --git a/src/EntityDb.SqlDb/Queries/SortBuilders/LeaseSortBuilder.cs b/src/EntityDb.SqlDb/Queries/SortBuilders/LeaseSortBuilder.cs new file mode 100644 index 00000000..853ea076 --- /dev/null +++ b/src/EntityDb.SqlDb/Queries/SortBuilders/LeaseSortBuilder.cs @@ -0,0 +1,38 @@ +using EntityDb.Abstractions.Queries.SortBuilders; +using EntityDb.SqlDb.Documents.Lease; +using EntityDb.SqlDb.Queries.Definitions.Sort; + +namespace EntityDb.SqlDb.Queries.SortBuilders; + +internal sealed class LeaseSortBuilder : SortBuilderBase, ILeaseSortBuilder +{ + public ISortDefinition EntityId(bool ascending) + { + return Sort(ascending, nameof(LeaseDocument.EntityId)); + } + + public ISortDefinition EntityVersionNumber(bool ascending) + { + return Sort(ascending, nameof(LeaseDocument.EntityVersionNumber)); + } + + public ISortDefinition LeaseType(bool ascending) + { + return SortDataType(ascending); + } + + public ISortDefinition LeaseScope(bool ascending) + { + return Sort(ascending, nameof(LeaseDocument.Scope)); + } + + public ISortDefinition LeaseLabel(bool ascending) + { + return Sort(ascending, nameof(LeaseDocument.Label)); + } + + public ISortDefinition LeaseValue(bool ascending) + { + return Sort(ascending, nameof(LeaseDocument.Value)); + } +} diff --git a/src/EntityDb.SqlDb/Queries/SortBuilders/SortBuilderBase.cs b/src/EntityDb.SqlDb/Queries/SortBuilders/SortBuilderBase.cs new file mode 100644 index 00000000..86488707 --- /dev/null +++ b/src/EntityDb.SqlDb/Queries/SortBuilders/SortBuilderBase.cs @@ -0,0 +1,36 @@ +using EntityDb.Abstractions.Queries.SortBuilders; +using EntityDb.SqlDb.Documents; +using EntityDb.SqlDb.Queries.Definitions.Sort; + +namespace EntityDb.SqlDb.Queries.SortBuilders; + +internal abstract class SortBuilderBase : ISortBuilder +{ + public ISortDefinition TransactionTimeStamp(bool ascending) + { + return Sort(ascending, nameof(ITransactionDocument.TransactionTimeStamp)); + } + + public ISortDefinition TransactionId(bool ascending) + { + return Sort(ascending, nameof(ITransactionDocument.TransactionId)); + } + + + public ISortDefinition Combine(params ISortDefinition[] sorts) + { + return new CombineSortDefinition(sorts); + } + + protected static ISortDefinition SortDataType(bool ascending) + { + return Sort(ascending, nameof(ITransactionDocument.DataType)); + } + + protected static ISortDefinition Sort(bool ascending, string fieldName) + { + return ascending + ? new AscSortDefinition(fieldName) + : new DescSortDefinition(fieldName); + } +} diff --git a/src/EntityDb.SqlDb/Queries/SortBuilders/TagSortBuilder.cs b/src/EntityDb.SqlDb/Queries/SortBuilders/TagSortBuilder.cs new file mode 100644 index 00000000..55f8d1f8 --- /dev/null +++ b/src/EntityDb.SqlDb/Queries/SortBuilders/TagSortBuilder.cs @@ -0,0 +1,33 @@ +using EntityDb.Abstractions.Queries.SortBuilders; +using EntityDb.SqlDb.Documents.Tag; +using EntityDb.SqlDb.Queries.Definitions.Sort; + +namespace EntityDb.SqlDb.Queries.SortBuilders; + +internal sealed class TagSortBuilder : SortBuilderBase, ITagSortBuilder +{ + public ISortDefinition EntityId(bool ascending) + { + return Sort(ascending, nameof(TagDocument.EntityId)); + } + + public ISortDefinition EntityVersionNumber(bool ascending) + { + return Sort(ascending, nameof(TagDocument.EntityVersionNumber)); + } + + public ISortDefinition TagType(bool ascending) + { + return SortDataType(ascending); + } + + public ISortDefinition TagLabel(bool ascending) + { + return Sort(ascending, nameof(TagDocument.Label)); + } + + public ISortDefinition TagValue(bool ascending) + { + return Sort(ascending, nameof(TagDocument.Value)); + } +} diff --git a/src/EntityDb.SqlDb/Sessions/ISqlDbSession.cs b/src/EntityDb.SqlDb/Sessions/ISqlDbSession.cs new file mode 100644 index 00000000..029229bb --- /dev/null +++ b/src/EntityDb.SqlDb/Sessions/ISqlDbSession.cs @@ -0,0 +1,46 @@ +using EntityDb.Abstractions.Disposables; +using EntityDb.SqlDb.Documents; +using EntityDb.SqlDb.Queries.Definitions.Filter; +using EntityDb.SqlDb.Queries.Definitions.Sort; +using System.Data.Common; + +namespace EntityDb.SqlDb.Sessions; + +internal interface ISqlDbSession : IDisposableResource + where TOptions : class +{ + DbConnection DbConnection { get; } + + Task Insert + ( + + string tableName, + TDocument[] documents, + CancellationToken cancellationToken + ) where TDocument : ITransactionDocument; + + IAsyncEnumerable Find + ( + IDocumentReader documentReader, + IFilterDefinition filterDefinition, + ISortDefinition? sortDefinition, + int? skip, + int? limit, + TOptions? options, + CancellationToken cancellationToken + ) + where TDocument : ITransactionDocument; + + Task Delete + ( + string tableName, + IFilterDefinition filterDefinition, + CancellationToken cancellationToken + ); + + Task StartTransaction(CancellationToken cancellationToken = default); + Task CommitTransaction(CancellationToken cancellationToken = default); + Task AbortTransaction(CancellationToken cancellationToken = default); + + ISqlDbSession WithTransactionSessionOptions(SqlDbTransactionSessionOptions transactionSessionOptions); +} diff --git a/src/EntityDb.SqlDb/Sessions/SqlDbSession.cs b/src/EntityDb.SqlDb/Sessions/SqlDbSession.cs new file mode 100644 index 00000000..c9451ff5 --- /dev/null +++ b/src/EntityDb.SqlDb/Sessions/SqlDbSession.cs @@ -0,0 +1,229 @@ +using EntityDb.Common.Disposables; +using EntityDb.Common.Exceptions; +using EntityDb.SqlDb.Converters; +using EntityDb.SqlDb.Documents; +using EntityDb.SqlDb.Queries.Definitions.Filter; +using EntityDb.SqlDb.Queries.Definitions.Sort; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using System.Data.Common; +using System.Runtime.CompilerServices; + +namespace EntityDb.SqlDb.Sessions; + +internal class SqlDbSession : DisposableResourceBaseClass, + ISqlDbSession + where TOptions : class +{ + private readonly ILogger> _logger; + private readonly ISqlConverter _sqlConverter; + private readonly SqlDbTransactionSessionOptions _options; + + private DbTransaction? _dbTransaction = default!; + + public DbConnection DbConnection { get; } + + public SqlDbSession + ( + ILogger> logger, + ISqlConverter sqlConverter, + SqlDbTransactionSessionOptions options, + DbConnection dbConnection + ) + { + _logger = logger; + _sqlConverter = sqlConverter; + _options = options; + + DbConnection = dbConnection; + } + + public async Task Insert + ( + string tableName, + TDocument[] documents, + CancellationToken cancellationToken + ) + where TDocument : ITransactionDocument + { + AssertNotReadOnly(); + + var dbCommand = _sqlConverter.ConvertInsert(tableName, documents); + + dbCommand.Connection = DbConnection; + dbCommand.Transaction = _dbTransaction; + + _logger + .LogInformation + ( + "Started Running {SqlType} Insert on `{Database}.{TableName}`\n\nCommand: {Command}\n\nDocuments Inserted: {DocumentsInserted}", + _sqlConverter.SqlType, + DbConnection.Database, + tableName, + dbCommand.CommandText, + documents.Length + ); + + await dbCommand.PrepareAsync(cancellationToken); + + var insertCount = await dbCommand.ExecuteNonQueryAsync(cancellationToken); + + _logger + .LogInformation + ( + "Finished Running {SqlType} Insert on `{Database}.{TableName}`\n\nCommand: {Command}\n\nDocuments Inserted: {DocumentsInserted}", + _sqlConverter.SqlType, + DbConnection.Database, + tableName, + dbCommand.CommandText, + insertCount + ); + } + + public async IAsyncEnumerable Find + ( + IDocumentReader documentReader, + IFilterDefinition filterDefintiion, + ISortDefinition? sortDefinition, + int? skip, + int? limit, + TOptions? options, + [EnumeratorCancellation] CancellationToken cancellationToken + ) + where TDocument : ITransactionDocument + { + var tableName = TDocument.TableName; + + var dbQuery = _sqlConverter.ConvertQuery(tableName, documentReader, filterDefintiion, sortDefinition, skip, limit, options); + + dbQuery.Connection = DbConnection; + dbQuery.Transaction = _dbTransaction; + + _logger + .LogInformation + ( + "Started Enumerating {SqlType} Query on `{Database}.{TableName}`\n\nQuery: {Query}", + _sqlConverter.SqlType, + DbConnection.Database, + tableName, + dbQuery.CommandText + ); + + ulong documentCount = 0; + + await dbQuery.PrepareAsync(cancellationToken); + + using var reader = await dbQuery.ExecuteReaderAsync(cancellationToken); + + while (await reader.ReadAsync(cancellationToken)) + { + documentCount += 1; + + yield return await documentReader.Read(reader, cancellationToken); + } + + _logger + .LogInformation + ( + "Finished Enumerating {SqlType} Query on `{Database}.{CollectionName}`\n\nQuery: {Query}\n\nDocuments Returned: {DocumentsReturned}", + _sqlConverter.SqlType, + DbConnection.Database, + tableName, + dbQuery.CommandText, + documentCount + ); + } + + public async Task Delete + ( + string tableName, + IFilterDefinition filterDefinition, + CancellationToken cancellationToken + ) + { + AssertNotReadOnly(); + + var dbCommand = _sqlConverter.ConvertDelete(tableName, filterDefinition); + + dbCommand.Connection = DbConnection; + dbCommand.Transaction = _dbTransaction; + + _logger + .LogInformation + ( + "Started Running {SqlType} Delete on `{Database}.{TableName}`\n\nCommand: {Command}", + _sqlConverter.SqlType, + DbConnection.Database, + tableName, + dbCommand.CommandText + ); + + await dbCommand.PrepareAsync(cancellationToken); + + var deletedCount = await dbCommand.ExecuteNonQueryAsync(cancellationToken); + + _logger + .LogInformation( + "Finished Running {SqlType} Delete on `{Database}.{TableName}`\n\nCommand: {Command}\n\nRows Deleted: {DocumentsDeleted}", + _sqlConverter.SqlType, + DbConnection.Database, + tableName, + dbCommand.CommandText, + deletedCount + ); + } + + public override async ValueTask DisposeAsync() + { + if (_dbTransaction != null) + { + await _dbTransaction.DisposeAsync(); + } + + await DbConnection.CloseAsync(); + await DbConnection.DisposeAsync(); + } + + private void AssertNotReadOnly() + { + if (_options.ReadOnly) + { + throw new CannotWriteInReadOnlyModeException(); + } + } + + public async Task StartTransaction(CancellationToken cancellationToken) + { + _dbTransaction = await DbConnection.BeginTransactionAsync(_options.IsolationLevel, cancellationToken); + } + + public async Task CommitTransaction(CancellationToken cancellationToken) + { + await _dbTransaction!.CommitAsync(cancellationToken); + } + + public async Task AbortTransaction(CancellationToken cancellationToken) + { + await _dbTransaction!.RollbackAsync(cancellationToken); + } + + public static ISqlDbSession Create + ( + IServiceProvider serviceProvider, + DbConnection dbConnection, + SqlDbTransactionSessionOptions options + ) + { + return ActivatorUtilities.CreateInstance> + ( + serviceProvider, + dbConnection, + options + ); + } + + public ISqlDbSession WithTransactionSessionOptions(SqlDbTransactionSessionOptions transactionSessionOptions) + { + return new SqlDbSession(_logger, _sqlConverter, transactionSessionOptions, DbConnection); + } +} diff --git a/src/EntityDb.SqlDb/Sessions/SqlDbTransactionSessionOptions.cs b/src/EntityDb.SqlDb/Sessions/SqlDbTransactionSessionOptions.cs new file mode 100644 index 00000000..24c05975 --- /dev/null +++ b/src/EntityDb.SqlDb/Sessions/SqlDbTransactionSessionOptions.cs @@ -0,0 +1,43 @@ +using EntityDb.Abstractions.Transactions; +using System.Data; + +namespace EntityDb.SqlDb.Sessions; + +/// +/// Configuration options for the PostgreSql implementation of . +/// +public class SqlDbTransactionSessionOptions +{ + /// + /// A connection string that is compatible with + /// + public string ConnectionString { get; set; } = default!; + + /// + /// If true, indicates the agent only intends to execute queries. + /// + public bool ReadOnly { get; set; } + + /// + /// If true, indicates the agent can tolerate replication lag for queries. + /// + public bool SecondaryPreferred { get; set; } + + public IsolationLevel IsolationLevel { get; set; } = IsolationLevel.Snapshot; + + /// + /// Determines how long to wait before a command should be automatically aborted. + /// + public TimeSpan WriteTimeout { get; set; } + + /// + /// Determines how long to wait before a query should be automatically killed. + /// + public TimeSpan? ReadTimeout { get; set; } + + /// + public override string ToString() + { + return $"{nameof(SqlDbTransactionSessionOptions)}"; + } +} diff --git a/src/EntityDb.SqlDb/Sessions/TestModeSqlDbSession.cs b/src/EntityDb.SqlDb/Sessions/TestModeSqlDbSession.cs new file mode 100644 index 00000000..6cc90e3f --- /dev/null +++ b/src/EntityDb.SqlDb/Sessions/TestModeSqlDbSession.cs @@ -0,0 +1,72 @@ +using EntityDb.Common.Disposables; +using EntityDb.SqlDb.Documents; +using EntityDb.SqlDb.Queries.Definitions.Filter; +using EntityDb.SqlDb.Queries.Definitions.Sort; +using System.Data.Common; + +namespace EntityDb.SqlDb.Sessions; + +internal record TestModeSqlDbSession(ISqlDbSession SqlDbSession) : DisposableResourceBaseRecord, ISqlDbSession + where TOptions : class +{ + public DbConnection DbConnection => SqlDbSession.DbConnection; + + public Task Insert(string tableName, TDocument[] bsonDocuments, CancellationToken cancellationToken) + where TDocument : ITransactionDocument + { + return SqlDbSession.Insert(tableName, bsonDocuments, cancellationToken); + } + + public IAsyncEnumerable Find + ( + IDocumentReader documentReader, + IFilterDefinition filterDefinition, + ISortDefinition? sortDefinition, + int? skip, + int? limit, + TOptions? options, + CancellationToken cancellationToken + ) + where TDocument : ITransactionDocument + { + return SqlDbSession.Find + ( + documentReader, + filterDefinition, + sortDefinition, + skip, + limit, + options, + cancellationToken + ); + } + + public Task Delete(string tableName, + IFilterDefinition filterDefinition, CancellationToken cancellationToken) + { + return SqlDbSession.Delete(tableName, filterDefinition, cancellationToken); + } + + public ISqlDbSession WithTransactionSessionOptions(SqlDbTransactionSessionOptions transactionSessionOptions) + { + return this with { SqlDbSession = SqlDbSession.WithTransactionSessionOptions(transactionSessionOptions) }; + } + + public Task StartTransaction(CancellationToken cancellationToken = default) + { + // Test Mode Transactions are started in the Test Mode Repository Factory + return Task.CompletedTask; + } + + public Task CommitTransaction(CancellationToken cancellationToken = default) + { + // Test Mode Transactions are never committed + return Task.CompletedTask; + } + + public Task AbortTransaction(CancellationToken cancellationToken = default) + { + // Test Mode Transactions are aborted in the Test Mode Repository Factory + return Task.CompletedTask; + } +} diff --git a/src/EntityDb.SqlDb/Transactions/ISqlDbTransactionRepositoryFactory.cs b/src/EntityDb.SqlDb/Transactions/ISqlDbTransactionRepositoryFactory.cs new file mode 100644 index 00000000..db2d7263 --- /dev/null +++ b/src/EntityDb.SqlDb/Transactions/ISqlDbTransactionRepositoryFactory.cs @@ -0,0 +1,25 @@ +using EntityDb.Abstractions.Transactions; +using EntityDb.SqlDb.Sessions; + +namespace EntityDb.SqlDb.Transactions; + +internal interface ISqlDbTransactionRepositoryFactory : ITransactionRepositoryFactory + where TOptions : class +{ + async Task ITransactionRepositoryFactory.CreateRepository( + string transactionSessionOptionsName, CancellationToken cancellationToken) + { + var options = GetTransactionSessionOptions(transactionSessionOptionsName); + + var sqlDbSession = await CreateSession(options, cancellationToken); + + return CreateRepository(sqlDbSession); + } + + SqlDbTransactionSessionOptions GetTransactionSessionOptions(string transactionSessionOptionsName); + + Task> CreateSession(SqlDbTransactionSessionOptions options, + CancellationToken cancellationToken); + + ITransactionRepository CreateRepository(ISqlDbSession sqlDbSession); +} diff --git a/src/EntityDb.SqlDb/Transactions/SqlDbTransactionRepository.cs b/src/EntityDb.SqlDb/Transactions/SqlDbTransactionRepository.cs new file mode 100644 index 00000000..922e0987 --- /dev/null +++ b/src/EntityDb.SqlDb/Transactions/SqlDbTransactionRepository.cs @@ -0,0 +1,247 @@ +using EntityDb.Abstractions.Annotations; +using EntityDb.Abstractions.Leases; +using EntityDb.Abstractions.Queries; +using EntityDb.Abstractions.Tags; +using EntityDb.Abstractions.Transactions; +using EntityDb.Abstractions.Transactions.Steps; +using EntityDb.Abstractions.ValueObjects; +using EntityDb.Common.Disposables; +using EntityDb.Common.Envelopes; +using EntityDb.Common.Exceptions; +using EntityDb.SqlDb.Documents.AgentSignature; +using EntityDb.SqlDb.Documents.Command; +using EntityDb.SqlDb.Documents.Lease; +using EntityDb.SqlDb.Documents.Tag; +using EntityDb.SqlDb.Extensions; +using EntityDb.SqlDb.Sessions; + +namespace EntityDb.SqlDb.Transactions; + +internal class SqlDbTransactionRepository : DisposableResourceBaseClass, ITransactionRepository + where TOptions : class +{ + private readonly IEnvelopeService _envelopeService; + private readonly ISqlDbSession _sqlDbSession; + + public SqlDbTransactionRepository + ( + ISqlDbSession sqlDbSession, + IEnvelopeService envelopeService + ) + { + _sqlDbSession = sqlDbSession; + _envelopeService = envelopeService; + } + + public IAsyncEnumerable EnumerateTransactionIds(IAgentSignatureQuery agentSignatureQuery, + CancellationToken cancellationToken = default) + { + return AgentSignatureDocument + .GetQuery(agentSignatureQuery) + .EnumerateTransactionIds(_sqlDbSession, cancellationToken); + } + + public IAsyncEnumerable EnumerateTransactionIds(ICommandQuery commandQuery, + CancellationToken cancellationToken = default) + { + return CommandDocument + .GetQuery(commandQuery) + .EnumerateTransactionIds(_sqlDbSession, cancellationToken); + } + + public IAsyncEnumerable EnumerateTransactionIds(ILeaseQuery leaseQuery, + CancellationToken cancellationToken = default) + { + return LeaseDocument + .GetQuery(leaseQuery) + .EnumerateTransactionIds(_sqlDbSession, cancellationToken); + } + + public IAsyncEnumerable EnumerateTransactionIds(ITagQuery tagQuery, + CancellationToken cancellationToken = default) + { + return TagDocument + .GetQuery(tagQuery) + .EnumerateTransactionIds(_sqlDbSession, cancellationToken); + } + + public IAsyncEnumerable EnumerateEntityIds(IAgentSignatureQuery agentSignatureQuery, + CancellationToken cancellationToken = default) + { + return AgentSignatureDocument + .GetQuery(agentSignatureQuery) + .EnumerateEntitiesIds(_sqlDbSession, cancellationToken); + } + + public IAsyncEnumerable EnumerateEntityIds(ICommandQuery commandQuery, + CancellationToken cancellationToken = default) + { + return CommandDocument + .GetQuery(commandQuery) + .EnumerateEntityIds(_sqlDbSession, cancellationToken); + } + + public IAsyncEnumerable EnumerateEntityIds(ILeaseQuery leaseQuery, + CancellationToken cancellationToken = default) + { + return LeaseDocument + .GetQuery(leaseQuery) + .EnumerateEntityIds(_sqlDbSession, cancellationToken); + } + + public IAsyncEnumerable EnumerateEntityIds(ITagQuery tagQuery, + CancellationToken cancellationToken = default) + { + return TagDocument + .GetQuery(tagQuery) + .EnumerateEntityIds(_sqlDbSession, cancellationToken); + } + + public IAsyncEnumerable EnumerateAgentSignatures(IAgentSignatureQuery agentSignatureQuery, + CancellationToken cancellationToken = default) + { + return AgentSignatureDocument + .GetQuery(agentSignatureQuery) + .EnumerateData(_sqlDbSession, _envelopeService, cancellationToken); + } + + public IAsyncEnumerable EnumerateCommands(ICommandQuery commandQuery, + CancellationToken cancellationToken = default) + { + return CommandDocument + .GetQuery(commandQuery) + .EnumerateData(_sqlDbSession, _envelopeService, cancellationToken); + } + + public IAsyncEnumerable EnumerateLeases(ILeaseQuery leaseQuery, + CancellationToken cancellationToken = default) + { + return LeaseDocument + .GetQuery(leaseQuery) + .EnumerateData(_sqlDbSession, _envelopeService, cancellationToken); + } + + public IAsyncEnumerable EnumerateTags(ITagQuery tagQuery, + CancellationToken cancellationToken = default) + { + return TagDocument + .GetQuery(tagQuery) + .EnumerateData(_sqlDbSession, _envelopeService, cancellationToken); + } + + public IAsyncEnumerable> EnumerateAnnotatedAgentSignatures(IAgentSignatureQuery agentSignatureQuery, + CancellationToken cancellationToken = default) + { + return AgentSignatureDocument + .GetQuery(agentSignatureQuery) + .EnumerateEntitiesAnnotation(_sqlDbSession, _envelopeService, cancellationToken); + } + + public IAsyncEnumerable> EnumerateAnnotatedCommands(ICommandQuery commandQuery, + CancellationToken cancellationToken = default) + { + return CommandDocument + .GetQuery(commandQuery) + .EnumerateEntityAnnotation(_sqlDbSession, _envelopeService, cancellationToken); + } + + public async Task PutTransaction(ITransaction transaction, CancellationToken cancellationToken = default) + { + try + { + await _sqlDbSession.StartTransaction(cancellationToken); + + await PutAgentSignature(transaction, cancellationToken); + + foreach (var transactionStep in transaction.Steps) + { + cancellationToken.ThrowIfCancellationRequested(); + + await (transactionStep switch + { + IAppendCommandTransactionStep appendCommandTransactionStep + => PutCommand(transaction, appendCommandTransactionStep, cancellationToken), + IAddLeasesTransactionStep addLeasesTransactionStep + => PutLeases(transaction, addLeasesTransactionStep, cancellationToken), + IAddTagsTransactionStep addTagsTransactionStep + => PutTags(transaction, addTagsTransactionStep, cancellationToken), + IDeleteLeasesTransactionStep deleteLeasesTransactionStep + => DeleteLeases(deleteLeasesTransactionStep, cancellationToken), + IDeleteTagsTransactionStep deleteTagsTransactionStep + => DeleteTags(deleteTagsTransactionStep, cancellationToken), + _ => throw new NotSupportedException() + }); + } + + await _sqlDbSession.CommitTransaction(cancellationToken); + + return true; + } + catch + { + await _sqlDbSession.AbortTransaction(cancellationToken); + + throw; + } + } + + public override async ValueTask DisposeAsync() + { + await _sqlDbSession.DisposeAsync(); + } + + private async Task PutAgentSignature(ITransaction transaction, CancellationToken cancellationToken) + { + await AgentSignatureDocument + .GetInsert(_envelopeService, transaction) + .Execute(_sqlDbSession, cancellationToken); + } + + private async Task PutCommand(ITransaction transaction, IAppendCommandTransactionStep appendCommandTransactionStep, + CancellationToken cancellationToken) + { + VersionZeroReservedException.ThrowIfZero(appendCommandTransactionStep.EntityVersionNumber); + + var previousVersionNumber = await CommandDocument + .GetLastEntityVersionNumber(_sqlDbSession, appendCommandTransactionStep.EntityId, cancellationToken); + + OptimisticConcurrencyException.ThrowIfMismatch(previousVersionNumber, + appendCommandTransactionStep.PreviousEntityVersionNumber); + + await CommandDocument + .GetInsert(_envelopeService, transaction, appendCommandTransactionStep) + .Execute(_sqlDbSession, cancellationToken); + } + + private async Task PutLeases(ITransaction transaction, IAddLeasesTransactionStep addLeasesTransactionStep, + CancellationToken cancellationToken) + { + await LeaseDocument + .GetInsert(_envelopeService, transaction, addLeasesTransactionStep) + .Execute(_sqlDbSession, cancellationToken); + } + + private async Task PutTags(ITransaction transaction, IAddTagsTransactionStep addTagsTransactionStep, + CancellationToken cancellationToken) + { + await TagDocument + .GetInsert(_envelopeService, transaction, addTagsTransactionStep) + .Execute(_sqlDbSession, cancellationToken); + } + + private async Task DeleteLeases(IDeleteLeasesTransactionStep deleteLeasesTransactionStep, + CancellationToken cancellationToken) + { + await LeaseDocument + .GetDeleteCommand(deleteLeasesTransactionStep) + .Execute(_sqlDbSession, cancellationToken); + } + + private async Task DeleteTags(IDeleteTagsTransactionStep deleteTagsTransactionStep, + CancellationToken cancellationToken) + { + await TagDocument + .GetDeleteCommand(deleteTagsTransactionStep) + .Execute(_sqlDbSession, cancellationToken); + } +} diff --git a/src/EntityDb.SqlDb/Transactions/SqlDbTransactionRepositoryFactoryWrapper.cs b/src/EntityDb.SqlDb/Transactions/SqlDbTransactionRepositoryFactoryWrapper.cs new file mode 100644 index 00000000..3761cf34 --- /dev/null +++ b/src/EntityDb.SqlDb/Transactions/SqlDbTransactionRepositoryFactoryWrapper.cs @@ -0,0 +1,42 @@ +using EntityDb.Abstractions.Transactions; +using EntityDb.Common.Disposables; +using EntityDb.SqlDb.Sessions; + +namespace EntityDb.SqlDb.Transactions; + +internal abstract class SqlDbTransactionRepositoryFactoryWrapper : DisposableResourceBaseClass, + ISqlDbTransactionRepositoryFactory + where TOptions : class +{ + private readonly ISqlDbTransactionRepositoryFactory _sqlDbTransactionRepositoryFactory; + + protected SqlDbTransactionRepositoryFactoryWrapper( + ISqlDbTransactionRepositoryFactory sqlDbTransactionRepositoryFactory) + { + _sqlDbTransactionRepositoryFactory = sqlDbTransactionRepositoryFactory; + } + + public virtual SqlDbTransactionSessionOptions GetTransactionSessionOptions(string transactionSessionOptionsName) + { + return _sqlDbTransactionRepositoryFactory.GetTransactionSessionOptions(transactionSessionOptionsName); + } + + public virtual Task> CreateSession(SqlDbTransactionSessionOptions options, + CancellationToken cancellationToken) + { + return _sqlDbTransactionRepositoryFactory.CreateSession(options, cancellationToken); + } + + public virtual ITransactionRepository CreateRepository + ( + ISqlDbSession sqlDbSession + ) + { + return _sqlDbTransactionRepositoryFactory.CreateRepository(sqlDbSession); + } + + public override async ValueTask DisposeAsync() + { + await _sqlDbTransactionRepositoryFactory.DisposeAsync(); + } +} diff --git a/src/EntityDb.SqlDb/Transactions/TestModeSqlDbTransactionRepositoryFactory.cs b/src/EntityDb.SqlDb/Transactions/TestModeSqlDbTransactionRepositoryFactory.cs new file mode 100644 index 00000000..64b2802b --- /dev/null +++ b/src/EntityDb.SqlDb/Transactions/TestModeSqlDbTransactionRepositoryFactory.cs @@ -0,0 +1,50 @@ +using EntityDb.SqlDb.Sessions; + +namespace EntityDb.SqlDb.Transactions; + +internal class + TestModeSqlDbTransactionRepositoryFactory : SqlDbTransactionRepositoryFactoryWrapper + where TOptions : class +{ + private (ISqlDbSession Normal, TestModeSqlDbSession TestMode)? _sessions; + + public TestModeSqlDbTransactionRepositoryFactory( + ISqlDbTransactionRepositoryFactory sqlDbTransactionRepositoryFactory) : base(sqlDbTransactionRepositoryFactory) + { + } + + public override async Task> CreateSession(SqlDbTransactionSessionOptions options, + CancellationToken cancellationToken) + { + if (_sessions.HasValue) + { + return _sessions.Value.TestMode + .WithTransactionSessionOptions(options); + } + + var normalOptions = new SqlDbTransactionSessionOptions + { + ConnectionString = options.ConnectionString + }; + + var normalSession = await base.CreateSession(normalOptions, cancellationToken); + + var testModeSession = new TestModeSqlDbSession(normalSession); + + await normalSession.StartTransaction(cancellationToken); + + _sessions = (normalSession, testModeSession); + + return _sessions.Value.TestMode + .WithTransactionSessionOptions(options); + } + + public override async ValueTask DisposeAsync() + { + if (_sessions.HasValue) + { + await _sessions.Value.Normal.AbortTransaction(); + await _sessions.Value.Normal.DisposeAsync(); + } + } +} diff --git a/src/EntityDb.SqlDb/packages.lock.json b/src/EntityDb.SqlDb/packages.lock.json new file mode 100644 index 00000000..68d5cb0e --- /dev/null +++ b/src/EntityDb.SqlDb/packages.lock.json @@ -0,0 +1,41 @@ +{ + "version": 1, + "dependencies": { + "net6.0": { + "System.Linq.Async": { + "type": "Direct", + "requested": "[6.0.1, )", + "resolved": "6.0.1", + "contentHash": "0YhHcaroWpQ9UCot3Pizah7ryAzQhNvobLMSxeDIGmnXfkQn8u5owvpOH0K6EVB+z9L7u6Cc4W17Br/+jyttEQ==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "6.0.0" + } + }, + "Microsoft.Bcl.AsyncInterfaces": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==" + }, + "entitydb.abstractions": { + "type": "Project", + "dependencies": { + "System.Linq.Async": "6.0.1" + } + }, + "entitydb.common": { + "type": "Project", + "dependencies": { + "EntityDb.Abstractions": "1.0.0", + "System.Linq.Async": "6.0.1" + } + }, + "entitydb.json": { + "type": "Project", + "dependencies": { + "EntityDb.Common": "1.0.0", + "System.Linq.Async": "6.0.1" + } + } + } + } +} \ No newline at end of file diff --git a/src/EntityDb.Void/Transactions/VoidTransactionRepository.cs b/src/EntityDb.Void/Transactions/VoidTransactionRepository.cs index b30d53fe..d1f2d774 100644 --- a/src/EntityDb.Void/Transactions/VoidTransactionRepository.cs +++ b/src/EntityDb.Void/Transactions/VoidTransactionRepository.cs @@ -5,104 +5,98 @@ using EntityDb.Abstractions.Transactions; using EntityDb.Abstractions.ValueObjects; using EntityDb.Common.Disposables; -using System; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.Void.Transactions; internal sealed class VoidTransactionRepository : DisposableResourceBaseClass, ITransactionRepository { - private static readonly Task EmptyIdArrayTask = Task.FromResult(Array.Empty()); - private static readonly Task EmptyObjectArrayTask = Task.FromResult(Array.Empty()); - private static readonly Task EmptyLeaseArrayTask = Task.FromResult(Array.Empty()); - private static readonly Task EmptyTagArrayTask = Task.FromResult(Array.Empty()); - - private static readonly Task[]> EmptyEntitiesAnnotationArrayTask = - Task.FromResult(Array.Empty>()); - - private static readonly Task[]> EmptyEntityAnnotationArrayTask = - Task.FromResult(Array.Empty>()); - - private static readonly Task TrueBoolTask = Task.FromResult(true); - - public Task GetTransactionIds(IAgentSignatureQuery agentSignatureQuery, + public IAsyncEnumerable EnumerateTransactionIds(IAgentSignatureQuery agentSignatureQuery, CancellationToken cancellationToken = default) { - return EmptyIdArrayTask.WaitAsync(cancellationToken); + return AsyncEnumerable.Empty(); } - public Task GetTransactionIds(ICommandQuery commandQuery, CancellationToken cancellationToken = default) + public IAsyncEnumerable EnumerateTransactionIds(ICommandQuery commandQuery, + CancellationToken cancellationToken = default) { - return EmptyIdArrayTask.WaitAsync(cancellationToken); + return AsyncEnumerable.Empty(); } - public Task GetTransactionIds(ILeaseQuery leaseQuery, CancellationToken cancellationToken = default) + public IAsyncEnumerable EnumerateTransactionIds(ILeaseQuery leaseQuery, + CancellationToken cancellationToken = default) { - return EmptyIdArrayTask.WaitAsync(cancellationToken); + return AsyncEnumerable.Empty(); } - public Task GetTransactionIds(ITagQuery tagQuery, CancellationToken cancellationToken = default) + public IAsyncEnumerable EnumerateTransactionIds(ITagQuery tagQuery, + CancellationToken cancellationToken = default) { - return EmptyIdArrayTask.WaitAsync(cancellationToken); + return AsyncEnumerable.Empty(); } - public Task GetEntityIds(IAgentSignatureQuery agentSignatureQuery, + public IAsyncEnumerable EnumerateEntityIds(IAgentSignatureQuery agentSignatureQuery, CancellationToken cancellationToken = default) { - return EmptyIdArrayTask.WaitAsync(cancellationToken); + return AsyncEnumerable.Empty(); } - public Task GetEntityIds(ICommandQuery commandQuery, CancellationToken cancellationToken = default) + public IAsyncEnumerable EnumerateEntityIds(ICommandQuery commandQuery, + CancellationToken cancellationToken = default) { - return EmptyIdArrayTask.WaitAsync(cancellationToken); + return AsyncEnumerable.Empty(); } - public Task GetEntityIds(ILeaseQuery leaseQuery, CancellationToken cancellationToken = default) + public IAsyncEnumerable EnumerateEntityIds(ILeaseQuery leaseQuery, + CancellationToken cancellationToken = default) { - return EmptyIdArrayTask.WaitAsync(cancellationToken); + return AsyncEnumerable.Empty(); } - public Task GetEntityIds(ITagQuery tagQuery, CancellationToken cancellationToken = default) + public IAsyncEnumerable EnumerateEntityIds(ITagQuery tagQuery, + CancellationToken cancellationToken = default) { - return EmptyIdArrayTask.WaitAsync(cancellationToken); + return AsyncEnumerable.Empty(); } - public Task GetAgentSignatures(IAgentSignatureQuery agentSignatureQuery, + public IAsyncEnumerable EnumerateAgentSignatures(IAgentSignatureQuery agentSignatureQuery, CancellationToken cancellationToken = default) { - return EmptyObjectArrayTask.WaitAsync(cancellationToken); + return AsyncEnumerable.Empty(); } - public Task GetCommands(ICommandQuery commandQuery, CancellationToken cancellationToken = default) + public IAsyncEnumerable EnumerateCommands(ICommandQuery commandQuery, + CancellationToken cancellationToken = default) { - return EmptyObjectArrayTask.WaitAsync(cancellationToken); + return AsyncEnumerable.Empty(); } - public Task GetLeases(ILeaseQuery leaseQuery, CancellationToken cancellationToken = default) + public IAsyncEnumerable EnumerateLeases(ILeaseQuery leaseQuery, + CancellationToken cancellationToken = default) { - return EmptyLeaseArrayTask.WaitAsync(cancellationToken); + return AsyncEnumerable.Empty(); } - public Task GetTags(ITagQuery tagQuery, CancellationToken cancellationToken = default) + public IAsyncEnumerable EnumerateTags(ITagQuery tagQuery, + CancellationToken cancellationToken = default) { - return EmptyTagArrayTask.WaitAsync(cancellationToken); + return AsyncEnumerable.Empty(); } - public Task[]> GetAnnotatedAgentSignatures(IAgentSignatureQuery agentSignatureQuery, + public IAsyncEnumerable> EnumerateAnnotatedAgentSignatures(IAgentSignatureQuery agentSignatureQuery, CancellationToken cancellationToken = default) { - return EmptyEntitiesAnnotationArrayTask.WaitAsync(cancellationToken); + return AsyncEnumerable.Empty>(); } - public Task[]> GetAnnotatedCommands(ICommandQuery commandQuery, + public IAsyncEnumerable> EnumerateAnnotatedCommands(ICommandQuery commandQuery, CancellationToken cancellationToken = default) { - return EmptyEntityAnnotationArrayTask.WaitAsync(cancellationToken); + return AsyncEnumerable.Empty>(); } - public Task PutTransaction(ITransaction transaction, CancellationToken cancellationToken = default) + public Task PutTransaction(ITransaction transaction, + CancellationToken cancellationToken = default) { - return TrueBoolTask.WaitAsync(cancellationToken); + return Task.FromResult(false); } } diff --git a/src/EntityDb.Void/Transactions/VoidTransactionRepositoryFactory.cs b/src/EntityDb.Void/Transactions/VoidTransactionRepositoryFactory.cs index 3fd73389..75a4f9ce 100644 --- a/src/EntityDb.Void/Transactions/VoidTransactionRepositoryFactory.cs +++ b/src/EntityDb.Void/Transactions/VoidTransactionRepositoryFactory.cs @@ -1,7 +1,5 @@ using EntityDb.Abstractions.Transactions; using EntityDb.Common.Disposables; -using System.Threading; -using System.Threading.Tasks; namespace EntityDb.Void.Transactions; diff --git a/src/EntityDb.Void/packages.lock.json b/src/EntityDb.Void/packages.lock.json index 8c9a5d5c..030ca5af 100644 --- a/src/EntityDb.Void/packages.lock.json +++ b/src/EntityDb.Void/packages.lock.json @@ -2,13 +2,31 @@ "version": 1, "dependencies": { "net6.0": { + "System.Linq.Async": { + "type": "Direct", + "requested": "[6.0.1, )", + "resolved": "6.0.1", + "contentHash": "0YhHcaroWpQ9UCot3Pizah7ryAzQhNvobLMSxeDIGmnXfkQn8u5owvpOH0K6EVB+z9L7u6Cc4W17Br/+jyttEQ==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "6.0.0" + } + }, + "Microsoft.Bcl.AsyncInterfaces": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==" + }, "entitydb.abstractions": { - "type": "Project" + "type": "Project", + "dependencies": { + "System.Linq.Async": "6.0.1" + } }, "entitydb.common": { "type": "Project", "dependencies": { - "EntityDb.Abstractions": "1.0.0" + "EntityDb.Abstractions": "1.0.0", + "System.Linq.Async": "6.0.1" } } } diff --git a/test/Directory.Build.props b/test/Directory.Build.props index 2a2551a2..918e38e4 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -15,18 +15,18 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all - - + + - - - - + + + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/test/EntityDb.Common.Tests/Agents/AgentAccessorTestsBase.cs b/test/EntityDb.Common.Tests/Agents/AgentAccessorTestsBase.cs index 339fb1e5..8cf0215b 100644 --- a/test/EntityDb.Common.Tests/Agents/AgentAccessorTestsBase.cs +++ b/test/EntityDb.Common.Tests/Agents/AgentAccessorTestsBase.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using EntityDb.Abstractions.Agents; +using EntityDb.Abstractions.Agents; using EntityDb.Common.Exceptions; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; diff --git a/test/EntityDb.Common.Tests/Agents/UnknownAgentAccessorTests.cs b/test/EntityDb.Common.Tests/Agents/UnknownAgentAccessorTests.cs index 24f7dc97..7da7c61c 100644 --- a/test/EntityDb.Common.Tests/Agents/UnknownAgentAccessorTests.cs +++ b/test/EntityDb.Common.Tests/Agents/UnknownAgentAccessorTests.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using EntityDb.Common.Agents; +using EntityDb.Common.Agents; using Microsoft.Extensions.DependencyInjection; namespace EntityDb.Common.Tests.Agents; diff --git a/test/EntityDb.Common.Tests/DatabaseContainerCollection.cs b/test/EntityDb.Common.Tests/DatabaseContainerCollection.cs new file mode 100644 index 00000000..7b760a2e --- /dev/null +++ b/test/EntityDb.Common.Tests/DatabaseContainerCollection.cs @@ -0,0 +1,8 @@ +using Xunit; + +namespace EntityDb.Common.Tests; + +[CollectionDefinition(nameof(DatabaseContainerCollection))] +public class DatabaseContainerCollection : ICollectionFixture +{ +} diff --git a/test/EntityDb.Common.Tests/DatabaseContainerFixture.cs b/test/EntityDb.Common.Tests/DatabaseContainerFixture.cs new file mode 100644 index 00000000..f7298901 --- /dev/null +++ b/test/EntityDb.Common.Tests/DatabaseContainerFixture.cs @@ -0,0 +1,67 @@ +using DotNet.Testcontainers.Builders; +using DotNet.Testcontainers.Configurations; +using DotNet.Testcontainers.Containers; +using Xunit; + +namespace EntityDb.Common.Tests; + +public class DatabaseContainerFixture : IAsyncLifetime +{ + private static readonly RedisTestcontainerConfiguration _redisConfiguration = new("redis:7.0.2"); + + private static readonly MongoDbTestcontainerConfiguration _mongoDbConfiguration = new("mongo:5.0.9") + { + Database = "entitydb", + Username = null, + Password = null + }; + + private static readonly string DockerVolumeMongoDbInit = Path.Combine + ( + AppDomain.CurrentDomain.BaseDirectory, + "DockerVolumes", + "MongoDb", + "Init" + ); + + private static readonly PostgreSqlTestcontainerConfiguration _postgreSqlConfiguration = new("postgres:12.6") + { + Database = "entitydb", + Username = "entitydb", + Password = "entitydb", + }; + + public RedisTestcontainerConfiguration RedisConfiguration => _redisConfiguration; + + public MongoDbTestcontainerConfiguration MongoDbConfiguration => _mongoDbConfiguration; + + public PostgreSqlTestcontainerConfiguration PostgreSqlConfiguration => _postgreSqlConfiguration; + + public RedisTestcontainer RedisContainer { get; } = new TestcontainersBuilder() + .WithDatabase(_redisConfiguration) + .Build(); + + public MongoDbTestcontainer MongoDbContainer { get; } = new TestcontainersBuilder() + .WithDatabase(_mongoDbConfiguration) + .WithBindMount(DockerVolumeMongoDbInit, "/docker-entrypoint-initdb.d") + .WithCommand("--replSet", "entitydb") + .Build(); + + public PostgreSqlTestcontainer PostgreSqlContainer { get; } = new TestcontainersBuilder() + .WithDatabase(_postgreSqlConfiguration) + .Build(); + + public async Task InitializeAsync() + { + await RedisContainer.StartAsync(); + await MongoDbContainer.StartAsync(); + await PostgreSqlContainer.StartAsync(); + } + + public async Task DisposeAsync() + { + await RedisContainer.DisposeAsync(); + await MongoDbContainer.DisposeAsync(); + await PostgreSqlContainer.DisposeAsync(); + } +} diff --git a/test/mongod-scripts/init.js b/test/EntityDb.Common.Tests/DockerVolumes/MongoDb/Init/init.js similarity index 100% rename from test/mongod-scripts/init.js rename to test/EntityDb.Common.Tests/DockerVolumes/MongoDb/Init/init.js diff --git a/test/EntityDb.Common.Tests/Entities/EntityTests.cs b/test/EntityDb.Common.Tests/Entities/EntityTests.cs index 0635e266..0a544d14 100644 --- a/test/EntityDb.Common.Tests/Entities/EntityTests.cs +++ b/test/EntityDb.Common.Tests/Entities/EntityTests.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using EntityDb.Abstractions.Entities; +using EntityDb.Abstractions.Entities; using EntityDb.Abstractions.Queries; using EntityDb.Abstractions.Snapshots; using EntityDb.Abstractions.Transactions; @@ -11,6 +7,7 @@ using EntityDb.Abstractions.ValueObjects; using EntityDb.Common.Entities; using EntityDb.Common.Exceptions; +using EntityDb.Common.Polyfills; using EntityDb.Common.Tests.Implementations.Commands; using EntityDb.Common.Tests.Implementations.Snapshots; using Microsoft.Extensions.DependencyInjection; @@ -20,9 +17,10 @@ namespace EntityDb.Common.Tests.Entities; +[Collection(nameof(DatabaseContainerCollection))] public class EntityTests : TestsBase { - public EntityTests(IServiceProvider serviceProvider) : base(serviceProvider) + public EntityTests(IServiceProvider serviceProvider, DatabaseContainerFixture databaseContainerFixture) : base(serviceProvider, databaseContainerFixture) { } @@ -127,8 +125,8 @@ private async Task Generic_GivenExistingEntityWithNoSnapshot_WhenGettingEntity_T .Returns(ValueTask.CompletedTask); transactionRepositoryMock - .Setup(repository => repository.GetCommands(It.IsAny(), It.IsAny())) - .ReturnsAsync(() => commands.ToArray()) + .Setup(repository => repository.EnumerateCommands(It.IsAny(), It.IsAny())) + .Returns(() => AsyncEnumerablePolyfill.FromResult(commands)) .Verifiable(); var transactionRepositoryFactoryMock = @@ -167,7 +165,7 @@ private async Task Generic_GivenExistingEntityWithNoSnapshot_WhenGettingEntity_T currenEntity.VersionNumber.ShouldBe(expectedVersionNumber); transactionRepositoryMock - .Verify(repository => repository.GetCommands(It.IsAny(), It.IsAny()), + .Verify(repository => repository.EnumerateCommands(It.IsAny(), It.IsAny()), Times.Once); } diff --git a/test/EntityDb.Common.Tests/EntityDb.Common.Tests.csproj b/test/EntityDb.Common.Tests/EntityDb.Common.Tests.csproj index 23190f87..07c076be 100644 --- a/test/EntityDb.Common.Tests/EntityDb.Common.Tests.csproj +++ b/test/EntityDb.Common.Tests/EntityDb.Common.Tests.csproj @@ -4,7 +4,18 @@ + + + + + + + + Always + + + diff --git a/test/EntityDb.Common.Tests/Envelopes/EnvelopeTestsBase.cs b/test/EntityDb.Common.Tests/Envelopes/EnvelopeTestsBase.cs index d0dd697a..10f5f284 100644 --- a/test/EntityDb.Common.Tests/Envelopes/EnvelopeTestsBase.cs +++ b/test/EntityDb.Common.Tests/Envelopes/EnvelopeTestsBase.cs @@ -1,5 +1,4 @@ -using System; -using EntityDb.Common.Envelopes; +using EntityDb.Common.Envelopes; using EntityDb.Common.Exceptions; using Microsoft.Extensions.DependencyInjection; using Shouldly; @@ -14,7 +13,7 @@ protected EnvelopeTestsBase(IServiceProvider startupServiceProvider) : base(star { } - protected abstract byte[] GenerateCorruptedBytes(); + protected abstract TEnvelopeValue GenerateCorruptedSerializedData(); [Fact] public void GivenValidRecord_WhenDeconstructedSerializedAndDeserialized_ThenReconstructReturnsEquivalentRecord() @@ -32,13 +31,9 @@ public void GivenValidRecord_WhenDeconstructedSerializedAndDeserialized_ThenReco var boxedRecord = (IRecord)record; - var envelope = envelopeService.Deconstruct(boxedRecord); + var envelope = envelopeService.Serialize(boxedRecord); - var rawData = envelopeService.Serialize(envelope); - - var reconstructedEnvelope = envelopeService.Deserialize(rawData); - - var reconstructedBoxedRecord = envelopeService.Reconstruct(reconstructedEnvelope); + var reconstructedBoxedRecord = envelopeService.Deserialize(envelope); var reconstructedRecord = (TestRecord)reconstructedBoxedRecord; @@ -48,41 +43,7 @@ public void GivenValidRecord_WhenDeconstructedSerializedAndDeserialized_ThenReco } [Fact] - public void WhenSerializingCorruptedEnvelope_ThrowSerializeException() - { - // ARRANGE - - using var serviceScope = CreateServiceScope(); - - var envelopeService = serviceScope.ServiceProvider - .GetRequiredService>(); - - var envelope = new Envelope(default!, default!); - - // ACT - - Should.Throw(() => { envelopeService.Serialize(envelope); }); - } - - [Fact] - public void WhenDeserializingCorruptedBytes_ThrowDeserializeException() - { - // ARRANGE - - using var serviceScope = CreateServiceScope(); - - var envelopeService = serviceScope.ServiceProvider - .GetRequiredService>(); - - var corruptedBytes = GenerateCorruptedBytes(); - - // ASSERT - - Should.Throw(() => { envelopeService.Deserialize(corruptedBytes); }); - } - - [Fact] - public void WhenReconstructingCorruptedEnvelope_ThrowDeserializeException() + public void WhenDeserializingCorruptedEnvelope_ThrowDeserializeException() { // ARRANGE @@ -91,15 +52,15 @@ public void WhenReconstructingCorruptedEnvelope_ThrowDeserializeException() var envelopeService = serviceScope.ServiceProvider .GetRequiredService>(); - var envelope = new Envelope(default!, default!); + var corruptedSerializedData = GenerateCorruptedSerializedData(); // ASSERT - Should.Throw(() => { envelopeService.Reconstruct(envelope); }); + Should.Throw(() => { envelopeService.Deserialize(corruptedSerializedData); }); } [Fact] - public void WhenDeconstructingNull_ThrowSerializeException() + public void WhenSerializingNull_ThrowSerializeException() { // ARRANGE @@ -110,7 +71,7 @@ public void WhenDeconstructingNull_ThrowSerializeException() // ASSERT - Should.Throw(() => { envelopeService.Deconstruct(null); }); + Should.Throw(() => { envelopeService.Serialize(null); }); } private interface IRecord diff --git a/test/EntityDb.Common.Tests/Extensions/FilterBuilderExtensions.cs b/test/EntityDb.Common.Tests/Extensions/FilterBuilderExtensions.cs index a47fa1bc..45f315bf 100644 --- a/test/EntityDb.Common.Tests/Extensions/FilterBuilderExtensions.cs +++ b/test/EntityDb.Common.Tests/Extensions/FilterBuilderExtensions.cs @@ -1,5 +1,4 @@ -using System.Linq; -using EntityDb.Abstractions.Queries.FilterBuilders; +using EntityDb.Abstractions.Queries.FilterBuilders; using EntityDb.Common.Extensions; using Moq; using Shouldly; diff --git a/test/EntityDb.Common.Tests/Implementations/Agents/CounterAgentSignature.cs b/test/EntityDb.Common.Tests/Implementations/Agents/CounterAgentSignature.cs deleted file mode 100644 index 364f91ac..00000000 --- a/test/EntityDb.Common.Tests/Implementations/Agents/CounterAgentSignature.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace EntityDb.Common.Tests.Implementations.Agents; - -public record CounterAgentSignature(ulong Number); \ No newline at end of file diff --git a/test/EntityDb.Common.Tests/Implementations/Commands/Count.cs b/test/EntityDb.Common.Tests/Implementations/Commands/StoreNumber.cs similarity index 86% rename from test/EntityDb.Common.Tests/Implementations/Commands/Count.cs rename to test/EntityDb.Common.Tests/Implementations/Commands/StoreNumber.cs index ab42232b..51423dc6 100644 --- a/test/EntityDb.Common.Tests/Implementations/Commands/Count.cs +++ b/test/EntityDb.Common.Tests/Implementations/Commands/StoreNumber.cs @@ -4,7 +4,7 @@ namespace EntityDb.Common.Tests.Implementations.Commands; -public record Count(ulong Number) : IReducer, IReducer +public record StoreNumber(ulong Number) : IReducer, IReducer { public OneToOneProjection Reduce(OneToOneProjection projection) { diff --git a/test/EntityDb.Common.Tests/Implementations/Entities/TestEntity.cs b/test/EntityDb.Common.Tests/Implementations/Entities/TestEntity.cs index 9e85de29..72a8cd6d 100644 --- a/test/EntityDb.Common.Tests/Implementations/Entities/TestEntity.cs +++ b/test/EntityDb.Common.Tests/Implementations/Entities/TestEntity.cs @@ -1,7 +1,4 @@ -using System; -using System.Linq; -using System.Threading; -using EntityDb.Abstractions.ValueObjects; +using EntityDb.Abstractions.ValueObjects; using EntityDb.Common.Entities; using EntityDb.Common.Tests.Implementations.Commands; using EntityDb.Common.Tests.Implementations.Snapshots; @@ -30,14 +27,14 @@ public VersionNumber GetVersionNumber() return VersionNumber; } - public TestEntity Reduce(object[] commands) + public TestEntity Reduce(object command) { - return commands.Aggregate(this, (previousEntity, nextCommand) => nextCommand switch + return command switch { - DoNothing doNothing => doNothing.Reduce(previousEntity), - Count count => count.Reduce(previousEntity), + DoNothing doNothing => doNothing.Reduce(this), + StoreNumber storeNumber => storeNumber.Reduce(this), _ => throw new NotSupportedException() - }); + }; } public bool ShouldRecord() diff --git a/test/EntityDb.Common.Tests/Implementations/Leases/CountLease.cs b/test/EntityDb.Common.Tests/Implementations/Leases/CountLease.cs index 2cc3580a..442d23cd 100644 --- a/test/EntityDb.Common.Tests/Implementations/Leases/CountLease.cs +++ b/test/EntityDb.Common.Tests/Implementations/Leases/CountLease.cs @@ -4,7 +4,7 @@ namespace EntityDb.Common.Tests.Implementations.Leases; public record CountLease(ulong Number) : ILease { - public string Scope => $"{Number}"; + public string Scope => ""; public string Label => ""; - public string Value => ""; + public string Value => $"{Number}"; } \ No newline at end of file diff --git a/test/EntityDb.Common.Tests/Implementations/Projections/OneToOneProjection.cs b/test/EntityDb.Common.Tests/Implementations/Projections/OneToOneProjection.cs index 1a70b2ef..8a3cd23b 100644 --- a/test/EntityDb.Common.Tests/Implementations/Projections/OneToOneProjection.cs +++ b/test/EntityDb.Common.Tests/Implementations/Projections/OneToOneProjection.cs @@ -1,6 +1,3 @@ -using System; -using System.Linq; -using System.Threading; using EntityDb.Abstractions.Annotations; using EntityDb.Abstractions.Queries; using EntityDb.Abstractions.Reducers; @@ -34,17 +31,16 @@ public VersionNumber GetVersionNumber() return VersionNumber; } - public OneToOneProjection Reduce(params IEntityAnnotation[] annotatedCommands) + public OneToOneProjection Reduce(IEntityAnnotation annotatedCommand) { - return annotatedCommands.Aggregate(this, (previousProjection, nextAnnotatedCommand) => - nextAnnotatedCommand switch + return annotatedCommand switch + { + IEntityAnnotation> reducer => reducer.Data.Reduce(this) with { - IEntityAnnotation> reducer => reducer.Data.Reduce(previousProjection) with - { - EntityVersionNumber = reducer.EntityVersionNumber - }, - _ => throw new NotSupportedException() - }); + EntityVersionNumber = reducer.EntityVersionNumber + }, + _ => throw new NotSupportedException() + }; } public bool ShouldRecord() diff --git a/test/EntityDb.Common.Tests/Implementations/Queries/CountQuery.cs b/test/EntityDb.Common.Tests/Implementations/Queries/CountQuery.cs index 8dcfb7c7..09d9713c 100644 --- a/test/EntityDb.Common.Tests/Implementations/Queries/CountQuery.cs +++ b/test/EntityDb.Common.Tests/Implementations/Queries/CountQuery.cs @@ -1,69 +1,29 @@ using EntityDb.Abstractions.Queries; using EntityDb.Abstractions.Queries.FilterBuilders; using EntityDb.Abstractions.Queries.SortBuilders; -using EntityDb.Common.Leases; -using EntityDb.Common.Tags; -using EntityDb.Common.Tests.Implementations.Agents; -using EntityDb.Common.Tests.Implementations.Commands; using EntityDb.Common.Tests.Implementations.Leases; using EntityDb.Common.Tests.Implementations.Tags; namespace EntityDb.Common.Tests.Implementations.Queries; -public record CountQuery(ulong Gte, ulong Lte) : IAgentSignatureQuery, ICommandQuery, ILeaseQuery, - ITagQuery +public record CountQuery(ulong Gte, ulong Lte, object? Options = null) : ILeaseQuery, ITagQuery { - public TFilter GetFilter(IAgentSignatureFilterBuilder builder) - { - return builder.And - ( - builder.AgentSignatureTypeIn(typeof(CounterAgentSignature)), - builder.AgentSignatureMatches((CounterAgentSignature counter) => - Gte <= counter.Number && counter.Number <= Lte) - ); - } - - public TSort GetSort(IAgentSignatureSortBuilder builder) - { - return builder.Combine - ( - builder.EntityIds(true), - builder.AgentSignatureType(true), - builder.AgentSignatureProperty(true, (CounterAgentSignature counter) => counter.Number) - ); - } - public int? Skip => null; public int? Take => null; - public TFilter GetFilter(ICommandFilterBuilder builder) - { - return builder.And - ( - builder.CommandTypeIn(typeof(Count)), - builder.CommandMatches((Count count) => Gte <= count.Number && count.Number <= Lte) - ); - } - - public TSort GetSort(ICommandSortBuilder builder) - { - return builder.Combine - ( - builder.EntityId(true), - builder.EntityVersionNumber(true), - builder.CommandType(true), - builder.CommandProperty(true, (Count count) => count.Number) - ); - } - public TFilter GetFilter(ILeaseFilterBuilder builder) { return builder.And ( builder.LeaseTypeIn(typeof(CountLease)), - builder.LeaseMatches((CountLease countLease) => - Gte <= countLease.Number && countLease.Number <= Lte) + builder.Or + ( + Enumerable + .Range((int)Gte, (int)(Lte - Gte + 1)) + .Select(number => builder.LeaseValueEq(number.ToString())) + .ToArray() + ) ); } @@ -71,11 +31,7 @@ public TSort GetSort(ILeaseSortBuilder builder) { return builder.Combine ( - builder.EntityId(true), - builder.EntityVersionNumber(true), - builder.LeaseType(true), - builder.LeaseProperty(true, (CountLease countLease) => countLease.Number), - builder.LeaseProperty(true, (Lease lease) => lease.Scope) + builder.LeaseValue(true) ); } @@ -84,7 +40,13 @@ public TFilter GetFilter(ITagFilterBuilder builder) return builder.And ( builder.TagTypeIn(typeof(CountTag)), - builder.TagMatches((CountTag countTag) => Gte <= countTag.Number && countTag.Number <= Lte) + builder.Or + ( + Enumerable + .Range((int)Gte, (int)(Lte - Gte + 1)) + .Select(number => builder.TagValueEq(number.ToString())) + .ToArray() + ) ); } @@ -92,11 +54,7 @@ public TSort GetSort(ITagSortBuilder builder) { return builder.Combine ( - builder.EntityId(true), - builder.EntityVersionNumber(true), - builder.TagType(true), - builder.TagProperty(true, (CountTag countTag) => countTag.Number), - builder.TagProperty(true, (Tag tag) => tag.Label) + builder.TagValue(true) ); } } \ No newline at end of file diff --git a/test/EntityDb.Common.Tests/Implementations/Queries/EntityIdQuery.cs b/test/EntityDb.Common.Tests/Implementations/Queries/EntityIdQuery.cs index 167046c8..36fe9117 100644 --- a/test/EntityDb.Common.Tests/Implementations/Queries/EntityIdQuery.cs +++ b/test/EntityDb.Common.Tests/Implementations/Queries/EntityIdQuery.cs @@ -5,7 +5,7 @@ namespace EntityDb.Common.Tests.Implementations.Queries; -public record EntityIdQuery(Id EntityId) : IAgentSignatureQuery, ICommandQuery, ILeaseQuery, ITagQuery +public record EntityIdQuery(Id EntityId, object? Options = null) : IAgentSignatureQuery, ICommandQuery, ILeaseQuery, ITagQuery { public TFilter GetFilter(IAgentSignatureFilterBuilder builder) { diff --git a/test/EntityDb.Common.Tests/Implementations/Queries/EntityVersionNumberQuery.cs b/test/EntityDb.Common.Tests/Implementations/Queries/EntityVersionNumberQuery.cs index 62464873..43a82eec 100644 --- a/test/EntityDb.Common.Tests/Implementations/Queries/EntityVersionNumberQuery.cs +++ b/test/EntityDb.Common.Tests/Implementations/Queries/EntityVersionNumberQuery.cs @@ -5,7 +5,7 @@ namespace EntityDb.Common.Tests.Implementations.Queries; -public record EntityVersionNumberQuery(VersionNumber Gte, VersionNumber Lte) : ICommandQuery, ILeaseQuery, ITagQuery +public record EntityVersionNumberQuery(VersionNumber Gte, VersionNumber Lte, object? Options = null) : ICommandQuery, ILeaseQuery, ITagQuery { public TFilter GetFilter(ICommandFilterBuilder builder) { diff --git a/test/EntityDb.Common.Tests/Implementations/Queries/TransactionIdQuery.cs b/test/EntityDb.Common.Tests/Implementations/Queries/TransactionIdQuery.cs index df377c9e..484b7615 100644 --- a/test/EntityDb.Common.Tests/Implementations/Queries/TransactionIdQuery.cs +++ b/test/EntityDb.Common.Tests/Implementations/Queries/TransactionIdQuery.cs @@ -5,7 +5,7 @@ namespace EntityDb.Common.Tests.Implementations.Queries; -public record TransactionIdQuery(Id TransactionId) : IAgentSignatureQuery, ICommandQuery, ILeaseQuery, +public record TransactionIdQuery(Id TransactionId, object? Options = null) : IAgentSignatureQuery, ICommandQuery, ILeaseQuery, ITagQuery { public TFilter GetFilter(IAgentSignatureFilterBuilder builder) diff --git a/test/EntityDb.Common.Tests/Implementations/Queries/TransactionTimeStampQuery.cs b/test/EntityDb.Common.Tests/Implementations/Queries/TransactionTimeStampQuery.cs index 0e8f3e6c..0f407040 100644 --- a/test/EntityDb.Common.Tests/Implementations/Queries/TransactionTimeStampQuery.cs +++ b/test/EntityDb.Common.Tests/Implementations/Queries/TransactionTimeStampQuery.cs @@ -5,7 +5,7 @@ namespace EntityDb.Common.Tests.Implementations.Queries; -public record TransactionTimeStampQuery(TimeStamp Gte, TimeStamp Lte) : IAgentSignatureQuery, ICommandQuery, +public record TransactionTimeStampQuery(TimeStamp Gte, TimeStamp Lte, object? Options = null) : IAgentSignatureQuery, ICommandQuery, ILeaseQuery, ITagQuery { public TFilter GetFilter(IAgentSignatureFilterBuilder builder) diff --git a/test/EntityDb.Common.Tests/Implementations/Seeders/TransactionSeeder.cs b/test/EntityDb.Common.Tests/Implementations/Seeders/TransactionSeeder.cs index cf3e1490..a99939b2 100644 --- a/test/EntityDb.Common.Tests/Implementations/Seeders/TransactionSeeder.cs +++ b/test/EntityDb.Common.Tests/Implementations/Seeders/TransactionSeeder.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; using System.Collections.Immutable; -using System.Linq; using EntityDb.Abstractions.Transactions; using EntityDb.Abstractions.Transactions.Steps; using EntityDb.Abstractions.ValueObjects; diff --git a/test/EntityDb.Common.Tests/Implementations/Snapshots/ISnapshotWithTestLogic.cs b/test/EntityDb.Common.Tests/Implementations/Snapshots/ISnapshotWithTestLogic.cs index 87ce7ca1..ac669003 100644 --- a/test/EntityDb.Common.Tests/Implementations/Snapshots/ISnapshotWithTestLogic.cs +++ b/test/EntityDb.Common.Tests/Implementations/Snapshots/ISnapshotWithTestLogic.cs @@ -1,5 +1,3 @@ -using System; -using System.Threading; using EntityDb.Abstractions.ValueObjects; using EntityDb.Common.Snapshots; diff --git a/test/EntityDb.Common.Tests/Implementations/Tags/CountTag.cs b/test/EntityDb.Common.Tests/Implementations/Tags/CountTag.cs index 138cc869..b6030c5a 100644 --- a/test/EntityDb.Common.Tests/Implementations/Tags/CountTag.cs +++ b/test/EntityDb.Common.Tests/Implementations/Tags/CountTag.cs @@ -4,6 +4,6 @@ namespace EntityDb.Common.Tests.Implementations.Tags; public record CountTag(ulong Number) : ITag { - public string Label => $"{Number}"; - public string Value => ""; + public string Label => ""; + public string Value => $"{Number}"; } \ No newline at end of file diff --git a/test/EntityDb.Common.Tests/Projections/ProjectionsTests.cs b/test/EntityDb.Common.Tests/Projections/ProjectionsTests.cs index bc108a8d..fad30023 100644 --- a/test/EntityDb.Common.Tests/Projections/ProjectionsTests.cs +++ b/test/EntityDb.Common.Tests/Projections/ProjectionsTests.cs @@ -1,5 +1,3 @@ -using System; -using System.Threading.Tasks; using EntityDb.Abstractions.Entities; using EntityDb.Abstractions.Projections; using EntityDb.Abstractions.ValueObjects; @@ -14,9 +12,10 @@ namespace EntityDb.Common.Tests.Projections; +[Collection(nameof(DatabaseContainerCollection))] public class ProjectionsTests : TestsBase { - public ProjectionsTests(IServiceProvider startupServiceProvider) : base(startupServiceProvider) + public ProjectionsTests(IServiceProvider startupServiceProvider, DatabaseContainerFixture databaseContainerFixture) : base(startupServiceProvider, databaseContainerFixture) { } diff --git a/test/EntityDb.Common.Tests/Snapshots/SnapshotTests.cs b/test/EntityDb.Common.Tests/Snapshots/SnapshotTests.cs index b7794c85..f5fccc57 100644 --- a/test/EntityDb.Common.Tests/Snapshots/SnapshotTests.cs +++ b/test/EntityDb.Common.Tests/Snapshots/SnapshotTests.cs @@ -1,6 +1,4 @@ -using System; -using System.Threading.Tasks; -using EntityDb.Abstractions.Snapshots; +using EntityDb.Abstractions.Snapshots; using EntityDb.Abstractions.ValueObjects; using EntityDb.Common.Exceptions; using EntityDb.Common.Tests.Implementations.Snapshots; @@ -13,9 +11,10 @@ namespace EntityDb.Common.Tests.Snapshots; +[Collection(nameof(DatabaseContainerCollection))] public sealed class SnapshotTests : TestsBase { - public SnapshotTests(IServiceProvider startupServiceProvider) : base(startupServiceProvider) + public SnapshotTests(IServiceProvider startupServiceProvider, DatabaseContainerFixture databaseContainerFixture) : base(startupServiceProvider, databaseContainerFixture) { } diff --git a/test/EntityDb.Common.Tests/Snapshots/TryCatchSnapshotRepositoryTests.cs b/test/EntityDb.Common.Tests/Snapshots/TryCatchSnapshotRepositoryTests.cs index 93daaa45..50e7437d 100644 --- a/test/EntityDb.Common.Tests/Snapshots/TryCatchSnapshotRepositoryTests.cs +++ b/test/EntityDb.Common.Tests/Snapshots/TryCatchSnapshotRepositoryTests.cs @@ -1,7 +1,4 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using EntityDb.Abstractions.Snapshots; +using EntityDb.Abstractions.Snapshots; using EntityDb.Abstractions.ValueObjects; using EntityDb.Common.Entities; using EntityDb.Common.Snapshots; diff --git a/test/EntityDb.Common.Tests/StartupBase.cs b/test/EntityDb.Common.Tests/StartupBase.cs index 7fc29244..86c466b3 100644 --- a/test/EntityDb.Common.Tests/StartupBase.cs +++ b/test/EntityDb.Common.Tests/StartupBase.cs @@ -1,5 +1,4 @@ -using System; -using EntityDb.Common.Agents; +using EntityDb.Common.Agents; using EntityDb.Common.Extensions; using Microsoft.Extensions.DependencyInjection; diff --git a/test/EntityDb.Common.Tests/TestLogger.cs b/test/EntityDb.Common.Tests/TestLogger.cs index 3d144719..41f9bd53 100644 --- a/test/EntityDb.Common.Tests/TestLogger.cs +++ b/test/EntityDb.Common.Tests/TestLogger.cs @@ -1,4 +1,3 @@ -using System; using Microsoft.Extensions.Logging; using Xunit.Abstractions; diff --git a/test/EntityDb.Common.Tests/TestsBase.cs b/test/EntityDb.Common.Tests/TestsBase.cs index 150f3bbd..5caa374a 100644 --- a/test/EntityDb.Common.Tests/TestsBase.cs +++ b/test/EntityDb.Common.Tests/TestsBase.cs @@ -1,15 +1,12 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; +using System.Diagnostics; using System.Reflection; -using System.Threading; -using System.Threading.Tasks; using EntityDb.Abstractions.Queries; using EntityDb.Abstractions.Snapshots; using EntityDb.Abstractions.Transactions; +using EntityDb.Abstractions.ValueObjects; using EntityDb.Common.Entities; using EntityDb.Common.Extensions; +using EntityDb.Common.Polyfills; using EntityDb.Common.Projections; using EntityDb.Common.Tests.Implementations.Entities; using EntityDb.Common.Tests.Implementations.Projections; @@ -17,12 +14,17 @@ using EntityDb.InMemory.Extensions; using EntityDb.InMemory.Sessions; using EntityDb.MongoDb.Provisioner.Extensions; +using EntityDb.MongoDb.Queries; using EntityDb.MongoDb.Sessions; +using EntityDb.Npgsql.Provisioner.Extensions; +using EntityDb.Npgsql.Queries; using EntityDb.Redis.Extensions; using EntityDb.Redis.Sessions; +using EntityDb.SqlDb.Sessions; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using MongoDB.Driver; using Moq; using Shouldly; using Xunit.Abstractions; @@ -40,15 +42,26 @@ public class TestsBase private static readonly TransactionsAdder[] AllTransactionAdders = { - new("MongoDb", serviceCollection => + new("MongoDb", typeof(MongoDbQueryOptions), (timeStamp) => timeStamp.WithMillisecondPrecision(), serviceCollection => { + var databaseContainerFixture = serviceCollection + .Single(descriptor => descriptor.ServiceType == typeof(DatabaseContainerFixture)) + .ImplementationInstance as DatabaseContainerFixture; + serviceCollection.AddAutoProvisionMongoDbTransactions(true); + serviceCollection.Configure("Count", options => + { + options.FindOptions = new FindOptions + { + Collation = new Collation("en", numericOrdering: true) + }; + }); + serviceCollection.ConfigureAll(options => { - options.ConnectionString = "mongodb://127.0.0.1:27017/?connect=direct&replicaSet=entitydb"; - options.DatabaseName = "Test"; - options.ReadTimeout = TimeSpan.FromSeconds(1); + options.ConnectionString = databaseContainerFixture!.MongoDbContainer.ConnectionString.Replace("mongodb://:@", "mongodb://"); + options.DatabaseName = databaseContainerFixture.MongoDbConfiguration.Database; options.WriteTimeout = TimeSpan.FromSeconds(1); }); @@ -68,20 +81,59 @@ public class TestsBase options.ReadOnly = true; options.SecondaryPreferred = true; }); + }), + + new("Npgsql", typeof(NpgsqlQueryOptions), (timeStamp) => timeStamp.WithMicrosecondPrecision(), serviceCollection => + { + var databaseContainerFixture = serviceCollection + .Single(descriptor => descriptor.ServiceType == typeof(DatabaseContainerFixture)) + .ImplementationInstance as DatabaseContainerFixture; + + serviceCollection.AddAutoProvisionNpgsqlTransactions(true); + + serviceCollection.Configure("Count", options => + { + options.LeaseValueSortCollation = "numeric"; + options.TagValueSortCollation = "numeric"; + }); + + serviceCollection.ConfigureAll(options => + { + options.ConnectionString = $"{databaseContainerFixture!.PostgreSqlContainer.ConnectionString};Include Error Detail=true"; + }); + + serviceCollection.Configure(TestSessionOptions.Write, options => + { + options.ReadOnly = false; + }); + + serviceCollection.Configure(TestSessionOptions.ReadOnly, options => + { + options.ReadOnly = true; + options.SecondaryPreferred = false; + }); + + serviceCollection.Configure(TestSessionOptions.ReadOnlySecondaryPreferred, options => + { + options.ReadOnly = true; + options.SecondaryPreferred = true; + }); }) }; private readonly IConfiguration _configuration; private readonly ITest _test; private readonly ITestOutputHelperAccessor _testOutputHelperAccessor; + private readonly DatabaseContainerFixture? _databaseContainerFixture; - protected TestsBase(IServiceProvider startupServiceProvider) + protected TestsBase(IServiceProvider startupServiceProvider, DatabaseContainerFixture? databaseContainerFixture = null) { _configuration = startupServiceProvider.GetRequiredService(); _testOutputHelperAccessor = startupServiceProvider.GetRequiredService(); _test = (typeof(TestOutputHelper).GetField("test", ~BindingFlags.Public)!.GetValue(_testOutputHelperAccessor.Output) as ITest).ShouldNotBeNull(); + _databaseContainerFixture = databaseContainerFixture; } protected Task RunGenericTestAsync(Type[] typeArguments, object?[] invokeParameters) @@ -103,11 +155,15 @@ private static SnapshotAdder RedisSnapshotAdder() { return new SnapshotAdder($"Redis<{typeof(TSnapshot).Name}>", typeof(TSnapshot), serviceCollection => { + var databaseContainerFixture = serviceCollection + .Single(descriptor => descriptor.ServiceType == typeof(DatabaseContainerFixture)) + .ImplementationInstance as DatabaseContainerFixture; + serviceCollection.AddRedisSnapshots(true); serviceCollection.ConfigureAll>(options => { - options.ConnectionString = "127.0.0.1:6379"; + options.ConnectionString = databaseContainerFixture!.RedisContainer.ConnectionString; options.KeyNamespace = TSnapshot.RedisKeyNamespace; }); @@ -271,6 +327,11 @@ protected IServiceScope CreateServiceScope(Action? configure startup.AddServices(serviceCollection); + if (_databaseContainerFixture != null) + { + serviceCollection.AddSingleton(_databaseContainerFixture); + } + configureServices?.Invoke(serviceCollection); serviceCollection.AddSingleton(typeof(ILogger<>), typeof(TestLogger<>)); @@ -357,8 +418,8 @@ protected static ITransactionRepositoryFactory GetMockedTransactionRepositoryFac .ReturnsAsync(true); transactionRepositoryMock - .Setup(repository => repository.GetCommands(It.IsAny(), It.IsAny())) - .ReturnsAsync(commands); + .Setup(repository => repository.EnumerateCommands(It.IsAny(), It.IsAny())) + .Returns(AsyncEnumerablePolyfill.FromResult(commands)); transactionRepositoryMock .Setup(repository => repository.DisposeAsync()) @@ -418,7 +479,7 @@ public void Dispose() } } - public record TransactionsAdder(string Name, AddDependenciesDelegate AddDependencies) + public record TransactionsAdder(string Name, Type QueryOptionsType, Func FixTimeStamp, AddDependenciesDelegate AddDependencies) { public override string ToString() { diff --git a/test/EntityDb.Common.Tests/Transactions/EntitySnapshotTransactionSubscriberTests.cs b/test/EntityDb.Common.Tests/Transactions/EntitySnapshotTransactionSubscriberTests.cs index c3be9d31..9edfa1ca 100644 --- a/test/EntityDb.Common.Tests/Transactions/EntitySnapshotTransactionSubscriberTests.cs +++ b/test/EntityDb.Common.Tests/Transactions/EntitySnapshotTransactionSubscriberTests.cs @@ -1,5 +1,3 @@ -using System; -using System.Threading.Tasks; using EntityDb.Abstractions.Entities; using EntityDb.Abstractions.Snapshots; using EntityDb.Abstractions.ValueObjects; @@ -12,14 +10,13 @@ namespace EntityDb.Common.Tests.Transactions; +[Collection(nameof(DatabaseContainerCollection))] public class EntitySnapshotTransactionSubscriberTests : TestsBase { - public EntitySnapshotTransactionSubscriberTests(IServiceProvider startupServiceProvider) : base( - startupServiceProvider) + public EntitySnapshotTransactionSubscriberTests(IServiceProvider startupServiceProvider, DatabaseContainerFixture databaseContainerFixture) : base(startupServiceProvider, databaseContainerFixture) { } - private async Task Generic_GivenSnapshotShouldRecordAsMostRecentAlwaysReturnsTrue_WhenRunningEntitySnapshotTransactionSubscriber_ThenAlwaysWriteSnapshot< TEntity>( diff --git a/test/EntityDb.Common.Tests/Transactions/SingleEntityTransactionBuilderTests.cs b/test/EntityDb.Common.Tests/Transactions/SingleEntityTransactionBuilderTests.cs index 2da59d11..fdc3d3ab 100644 --- a/test/EntityDb.Common.Tests/Transactions/SingleEntityTransactionBuilderTests.cs +++ b/test/EntityDb.Common.Tests/Transactions/SingleEntityTransactionBuilderTests.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using EntityDb.Abstractions.Entities; +using EntityDb.Abstractions.Entities; using EntityDb.Abstractions.Transactions.Builders; using EntityDb.Abstractions.Transactions.Steps; using EntityDb.Abstractions.ValueObjects; diff --git a/test/EntityDb.Common.Tests/Transactions/TransactionTests.cs b/test/EntityDb.Common.Tests/Transactions/TransactionTests.cs index 225d42e4..c1a3c191 100644 --- a/test/EntityDb.Common.Tests/Transactions/TransactionTests.cs +++ b/test/EntityDb.Common.Tests/Transactions/TransactionTests.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using System.Threading.Tasks; +using System.Collections.Immutable; using EntityDb.Abstractions.Leases; using EntityDb.Abstractions.Queries; using EntityDb.Abstractions.Tags; @@ -10,6 +6,7 @@ using EntityDb.Abstractions.Transactions.Builders; using EntityDb.Abstractions.Transactions.Steps; using EntityDb.Abstractions.ValueObjects; +using EntityDb.Common.Agents; using EntityDb.Common.Entities; using EntityDb.Common.Exceptions; using EntityDb.Common.Extensions; @@ -17,7 +14,6 @@ using EntityDb.Common.Queries; using EntityDb.Common.Queries.Modified; using EntityDb.Common.Tags; -using EntityDb.Common.Tests.Implementations.Agents; using EntityDb.Common.Tests.Implementations.Commands; using EntityDb.Common.Tests.Implementations.Leases; using EntityDb.Common.Tests.Implementations.Queries; @@ -28,15 +24,17 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Moq; using Shouldly; using Xunit; namespace EntityDb.Common.Tests.Transactions; +[Collection(nameof(DatabaseContainerCollection))] public sealed class TransactionTests : TestsBase { - public TransactionTests(IServiceProvider startupServiceProvider) : base(startupServiceProvider) + public TransactionTests(IServiceProvider startupServiceProvider, DatabaseContainerFixture databaseContainerFixture) : base(startupServiceProvider, databaseContainerFixture) { } @@ -73,7 +71,7 @@ private static async Task TestGet ( IServiceScope serviceScope, Func getExpectedResults, - Func> getActualResults, + Func> getActualResults, bool secondaryPreferred ) { @@ -100,15 +98,15 @@ bool secondaryPreferred // ACT var actualTrueResults = - await getActualResults.Invoke(transactionRepository, bufferModifier); + await getActualResults.Invoke(transactionRepository, bufferModifier).ToArrayAsync(); var actualFalseResults = - await getActualResults.Invoke(transactionRepository, negateModifier); + await getActualResults.Invoke(transactionRepository, negateModifier).ToArrayAsync(); var reversedActualTrueResults = - await getActualResults.Invoke(transactionRepository, reverseBufferModifier); + await getActualResults.Invoke(transactionRepository, reverseBufferModifier).ToArrayAsync(); var reversedActualFalseResults = - await getActualResults.Invoke(transactionRepository, reverseNegateModifier); + await getActualResults.Invoke(transactionRepository, reverseNegateModifier).ToArrayAsync(); var actualSkipTakeResults = - await getActualResults.Invoke(transactionRepository, bufferSubsetModifier); + await getActualResults.Invoke(transactionRepository, bufferSubsetModifier).ToArrayAsync(); // ASSERT @@ -134,10 +132,10 @@ Id[] GetExpectedResults(bool invert) .ToArray(); } - Task GetActualResults(ITransactionRepository transactionRepository, + IAsyncEnumerable GetActualResults(ITransactionRepository transactionRepository, ModifiedQueryOptions modifiedQueryOptions) { - return transactionRepository.GetTransactionIds(query.Modify(modifiedQueryOptions)); + return transactionRepository.EnumerateTransactionIds(query.Modify(modifiedQueryOptions)); } await TestGet(serviceScope, GetExpectedResults, GetActualResults, true); @@ -159,10 +157,10 @@ Id[] GetExpectedResults(bool invert) .ToArray(); } - Task GetActualResults(ITransactionRepository transactionRepository, + IAsyncEnumerable GetActualResults(ITransactionRepository transactionRepository, ModifiedQueryOptions modifiedQueryOptions) { - return transactionRepository.GetTransactionIds(query.Modify(modifiedQueryOptions)); + return transactionRepository.EnumerateTransactionIds(query.Modify(modifiedQueryOptions)); } await TestGet(serviceScope, GetExpectedResults, GetActualResults, true); @@ -184,10 +182,10 @@ Id[] GetExpectedResults(bool invert) .ToArray(); } - Task GetActualResults(ITransactionRepository transactionRepository, + IAsyncEnumerable GetActualResults(ITransactionRepository transactionRepository, ModifiedQueryOptions modifiedQueryOptions) { - return transactionRepository.GetTransactionIds(query.Modify(modifiedQueryOptions)); + return transactionRepository.EnumerateTransactionIds(query.Modify(modifiedQueryOptions)); } await TestGet(serviceScope, GetExpectedResults, GetActualResults, true); @@ -209,10 +207,10 @@ Id[] GetExpectedResults(bool invert) .ToArray(); } - Task GetActualResults(ITransactionRepository transactionRepository, + IAsyncEnumerable GetActualResults(ITransactionRepository transactionRepository, ModifiedQueryOptions modifiedQueryOptions) { - return transactionRepository.GetTransactionIds(query.Modify(modifiedQueryOptions)); + return transactionRepository.EnumerateTransactionIds(query.Modify(modifiedQueryOptions)); } await TestGet(serviceScope, GetExpectedResults, GetActualResults, true); @@ -234,10 +232,10 @@ Id[] GetExpectedResults(bool invert) .ToArray(); } - Task GetActualResults(ITransactionRepository transactionRepository, + IAsyncEnumerable GetActualResults(ITransactionRepository transactionRepository, ModifiedQueryOptions modifiedQueryOptions) { - return transactionRepository.GetEntityIds(query.Modify(modifiedQueryOptions)); + return transactionRepository.EnumerateEntityIds(query.Modify(modifiedQueryOptions)); } await TestGet(serviceScope, GetExpectedResults, GetActualResults, true); @@ -259,10 +257,10 @@ Id[] GetExpectedResults(bool invert) .ToArray(); } - Task GetActualResults(ITransactionRepository transactionRepository, + IAsyncEnumerable GetActualResults(ITransactionRepository transactionRepository, ModifiedQueryOptions modifiedQueryOptions) { - return transactionRepository.GetEntityIds(query.Modify(modifiedQueryOptions)); + return transactionRepository.EnumerateEntityIds(query.Modify(modifiedQueryOptions)); } await TestGet(serviceScope, GetExpectedResults, GetActualResults, true); @@ -284,10 +282,10 @@ Id[] GetExpectedResults(bool invert) .ToArray(); } - Task GetActualResults(ITransactionRepository transactionRepository, + IAsyncEnumerable GetActualResults(ITransactionRepository transactionRepository, ModifiedQueryOptions modifiedQueryOptions) { - return transactionRepository.GetEntityIds(query.Modify(modifiedQueryOptions)); + return transactionRepository.EnumerateEntityIds(query.Modify(modifiedQueryOptions)); } await TestGet(serviceScope, GetExpectedResults, GetActualResults, true); @@ -309,10 +307,10 @@ Id[] GetExpectedResults(bool invert) .ToArray(); } - Task GetActualResults(ITransactionRepository transactionRepository, + IAsyncEnumerable GetActualResults(ITransactionRepository transactionRepository, ModifiedQueryOptions modifiedQueryOptions) { - return transactionRepository.GetEntityIds(query.Modify(modifiedQueryOptions)); + return transactionRepository.EnumerateEntityIds(query.Modify(modifiedQueryOptions)); } await TestGet(serviceScope, GetExpectedResults, GetActualResults, true); @@ -334,10 +332,10 @@ object[] GetExpectedResults(bool invert) .ToArray(); } - Task GetActualResults(ITransactionRepository transactionRepository, + IAsyncEnumerable GetActualResults(ITransactionRepository transactionRepository, ModifiedQueryOptions modifiedQueryOptions) { - return transactionRepository.GetAgentSignatures(query.Modify(modifiedQueryOptions)); + return transactionRepository.EnumerateAgentSignatures(query.Modify(modifiedQueryOptions)); } await TestGet(serviceScope, GetExpectedResults, GetActualResults, true); @@ -359,10 +357,10 @@ object[] GetExpectedResults(bool invert) .ToArray(); } - Task GetActualResults(ITransactionRepository transactionRepository, + IAsyncEnumerable GetActualResults(ITransactionRepository transactionRepository, ModifiedQueryOptions modifiedQueryOptions) { - return transactionRepository.GetCommands(query.Modify(modifiedQueryOptions)); + return transactionRepository.EnumerateCommands(query.Modify(modifiedQueryOptions)); } await TestGet(serviceScope, GetExpectedResults, GetActualResults, true); @@ -384,10 +382,10 @@ ILease[] GetExpectedResults(bool invert) .ToArray(); } - Task GetActualResults(ITransactionRepository transactionRepository, + IAsyncEnumerable GetActualResults(ITransactionRepository transactionRepository, ModifiedQueryOptions modifiedQueryOptions) { - return transactionRepository.GetLeases(query.Modify(modifiedQueryOptions)); + return transactionRepository.EnumerateLeases(query.Modify(modifiedQueryOptions)); } await TestGet(serviceScope, GetExpectedResults, GetActualResults, true); @@ -409,10 +407,10 @@ ITag[] GetExpectedResults(bool invert) .ToArray(); } - Task GetActualResults(ITransactionRepository transactionRepository, + IAsyncEnumerable GetActualResults(ITransactionRepository transactionRepository, ModifiedQueryOptions modifiedQueryOptions) { - return transactionRepository.GetTags(query.Modify(modifiedQueryOptions)); + return transactionRepository.EnumerateTags(query.Modify(modifiedQueryOptions)); } await TestGet(serviceScope, GetExpectedResults, GetActualResults, true); @@ -436,7 +434,7 @@ private static async Task BuildTransaction foreach (var count in counts) { - transactionBuilder.Append(new Count(count)); + transactionBuilder.Append(new StoreNumber(count)); transactionBuilder.Add(new CountLease(count)); transactionBuilder.Add(new CountTag(count)); } @@ -807,23 +805,14 @@ private async Task entityAdder.AddDependencies.Invoke(serviceCollection); }); - var transactionTimeStamp = TimeStamp.UtcNow; - var expectedTransactionId = Id.NewId(); var expectedEntityId = Id.NewId(); - var expectedTransactionTimeStamps = new[] - { - transactionTimeStamp, - - // A TimeStamp can be more precise than milliseconds. - // This allows for database types that cannot be more precise than milliseconds. - transactionTimeStamp.WithMillisecondPrecision() - }; + var expectedTransactionTimeStamp = transactionsAdder.FixTimeStamp(TimeStamp.UtcNow); - var agentSignature = new CounterAgentSignature(123); + var agentSignature = new UnknownAgentSignature(new Dictionary()); var transaction = await BuildTransaction(serviceScope, expectedTransactionId, expectedEntityId, - new[] { expectedCount }, transactionTimeStamp, agentSignature); + new[] { expectedCount }, expectedTransactionTimeStamp, agentSignature); await using var transactionRepository = await serviceScope.ServiceProvider .GetRequiredService() @@ -839,18 +828,17 @@ private async Task // ACT - var annotatedAgentSignatures = await transactionRepository.GetAnnotatedAgentSignatures(agentSignatureQuery); + var annotatedAgentSignatures = await transactionRepository.EnumerateAnnotatedAgentSignatures(agentSignatureQuery).ToArrayAsync(); // ASSERT annotatedAgentSignatures.Length.ShouldBe(1); annotatedAgentSignatures[0].TransactionId.ShouldBe(expectedTransactionId); + annotatedAgentSignatures[0].TransactionTimeStamp.ShouldBe(expectedTransactionTimeStamp); annotatedAgentSignatures[0].EntityIds.Length.ShouldBe(1); annotatedAgentSignatures[0].EntityIds[0].ShouldBe(expectedEntityId); - annotatedAgentSignatures[0].Data.ShouldBe(agentSignature); - - expectedTransactionTimeStamps.Contains(annotatedAgentSignatures[0].TransactionTimeStamp).ShouldBeTrue(); + annotatedAgentSignatures[0].Data.ShouldBeEquivalentTo(agentSignature); } private async Task Generic_GivenCommandInserted_WhenGettingAnnotatedCommand_ThenReturnAnnotatedCommand( @@ -867,21 +855,12 @@ private async Task Generic_GivenCommandInserted_WhenGettingAnnotatedCommand_Then entityAdder.AddDependencies.Invoke(serviceCollection); }); - var transactionTimeStamp = TimeStamp.UtcNow; - var expectedTransactionId = Id.NewId(); var expectedEntityId = Id.NewId(); - var expectedTransactionTimeStamps = new[] - { - transactionTimeStamp, - - // A TimeStamp can be more precise than milliseconds. - // This allows for database types that cannot be more precise than milliseconds. - transactionTimeStamp.WithMillisecondPrecision() - }; + var expectedTransactionTimeStamp = transactionsAdder.FixTimeStamp(TimeStamp.UtcNow); var transaction = await BuildTransaction(serviceScope, expectedTransactionId, expectedEntityId, - new[] { expectedCount }, transactionTimeStamp); + new[] { expectedCount }, expectedTransactionTimeStamp); await using var transactionRepository = await serviceScope.ServiceProvider .GetRequiredService() @@ -897,21 +876,20 @@ private async Task Generic_GivenCommandInserted_WhenGettingAnnotatedCommand_Then // ACT - var annotatedCommands = await transactionRepository.GetAnnotatedCommands(commandQuery); + var annotatedCommands = await transactionRepository.EnumerateAnnotatedCommands(commandQuery).ToArrayAsync(); // ASSERT annotatedCommands.Length.ShouldBe(1); annotatedCommands[0].TransactionId.ShouldBe(expectedTransactionId); + annotatedCommands[0].TransactionTimeStamp.ShouldBe(expectedTransactionTimeStamp); annotatedCommands[0].EntityId.ShouldBe(expectedEntityId); annotatedCommands[0].EntityVersionNumber.ShouldBe(new VersionNumber(1)); - var actualCountCommand = annotatedCommands[0].Data.ShouldBeAssignableTo().ShouldNotBeNull(); + var actualCountCommand = annotatedCommands[0].Data.ShouldBeAssignableTo().ShouldNotBeNull(); actualCountCommand.Number.ShouldBe(expectedCount); - - expectedTransactionTimeStamps.Contains(annotatedCommands[0].TransactionTimeStamp).ShouldBeTrue(); } private async Task Generic_GivenEntityInserted_WhenGettingEntity_ThenReturnEntity( @@ -993,7 +971,7 @@ private async Task Generic_GivenEntityInsertedWithTags_WhenRemovingAllTags_ThenF // ACT - var actualInitialTags = await transactionRepository.GetTags(tagQuery); + var actualInitialTags = await transactionRepository.EnumerateTags(tagQuery).ToArrayAsync(); var finalTransaction = transactionBuilder .Delete(tag) @@ -1001,7 +979,7 @@ private async Task Generic_GivenEntityInsertedWithTags_WhenRemovingAllTags_ThenF var finalTransactionInserted = await transactionRepository.PutTransaction(finalTransaction); - var actualFinalTags = await transactionRepository.GetTags(tagQuery); + var actualFinalTags = await transactionRepository.EnumerateTags(tagQuery).ToArrayAsync(); // ASSERT @@ -1052,7 +1030,7 @@ private async Task Generic_GivenEntityInsertedWithLeases_WhenRemovingAllLeases_T // ACT - var actualInitialLeases = await transactionRepository.GetLeases(leaseQuery); + var actualInitialLeases = await transactionRepository.EnumerateLeases(leaseQuery).ToArrayAsync(); var finalTransaction = transactionBuilder .Delete(lease) @@ -1060,7 +1038,7 @@ private async Task Generic_GivenEntityInsertedWithLeases_WhenRemovingAllLeases_T var finalTransactionInserted = await transactionRepository.PutTransaction(finalTransaction); - var actualFinalLeases = await transactionRepository.GetLeases(leaseQuery); + var actualFinalLeases = await transactionRepository.EnumerateLeases(leaseQuery).ToArrayAsync(); // ASSERT @@ -1084,7 +1062,7 @@ private async Task entityAdder.AddDependencies.Invoke(serviceCollection); }); - var expectedCommand = new Count(1); + var expectedCommand = new StoreNumber(1); var transactionBuilder = await serviceScope.ServiceProvider .GetRequiredService>() @@ -1104,7 +1082,7 @@ private async Task var transactionInserted = await transactionRepository.PutTransaction(transaction); - var newCommands = await transactionRepository.GetCommands(versionOneCommandQuery); + var newCommands = await transactionRepository.EnumerateCommands(versionOneCommandQuery).ToArrayAsync(); // ASSERT @@ -1135,14 +1113,14 @@ private async Task entityAdder.AddDependencies.Invoke(serviceCollection); }); - var expectedCommand = new Count(2); + var expectedCommand = new StoreNumber(2); var transactionBuilder = await serviceScope.ServiceProvider .GetRequiredService>() .CreateForSingleEntity(default!, default); var firstTransaction = transactionBuilder - .Append(new Count(1)) + .Append(new StoreNumber(1)) .Build(Id.NewId()); var secondTransaction = transactionBuilder @@ -1164,7 +1142,7 @@ private async Task var secondTransactionInserted = await transactionRepository.PutTransaction(secondTransaction); - var newCommands = await transactionRepository.GetCommands(versionTwoCommandQuery); + var newCommands = await transactionRepository.EnumerateCommands(versionTwoCommandQuery).ToArrayAsync(); // ASSERT @@ -1215,9 +1193,9 @@ private async Task var currentTimeStamp = new TimeStamp(originTimeStamp.Value.AddMinutes(i)); - var agentSignature = new CounterAgentSignature(i); + var agentSignature = new UnknownAgentSignature(new Dictionary()); - var commands = new object[] { new Count(i) }; + var commands = new object[] { new StoreNumber(i) }; var leases = new[] { new CountLease(i) }; @@ -1286,14 +1264,14 @@ private async Task var transactionIds = GetSortedIds((int)numberOfTransactionIds); var entityIds = GetSortedIds((int)numberOfTransactionIds); + var agentSignature = new UnknownAgentSignature(new Dictionary()); + for (var i = 1UL; i <= numberOfTransactionIds; i++) { var currentTransactionId = transactionIds[i - 1]; var currentEntityId = entityIds[i - 1]; - var agentSignature = new CounterAgentSignature(i); - - var commands = new object[] { new Count(i) }; + var commands = new object[] { new StoreNumber(i) }; var leases = new[] { new CountLease(i) }; @@ -1353,14 +1331,14 @@ private async Task var transactionIds = GetSortedIds((int)numberOfEntityIds); var entityIds = GetSortedIds((int)numberOfEntityIds); + var agentSignature = new UnknownAgentSignature(new Dictionary()); + for (var i = 1UL; i <= numberOfEntityIds; i++) { var currentTransactionId = transactionIds[i - 1]; var currentEntityId = entityIds[i - 1]; - var agentSignature = new CounterAgentSignature(i); - - var commands = new object[] { new Count(i) }; + var commands = new object[] { new StoreNumber(i) }; var leases = new[] { new CountLease(i) }; @@ -1417,7 +1395,7 @@ private async Task for (var i = 1UL; i <= numberOfVersionNumbers; i++) { - var command = new Count(i); + var command = new StoreNumber(i); var leases = new[] { new CountLease(i) }; @@ -1441,8 +1419,9 @@ private async Task await TestGetTags(serviceScope, query, expectedObjects); } - private async Task Generic_GivenTransactionAlreadyInserted_WhenQueryingByData_ThenReturnExpectedObjects( + private async Task Generic_GivenTransactionAlreadyInserted_WhenQueryingByData_ThenReturnExpectedObjects( TransactionsAdder transactionsAdder, EntityAdder entityAdder) + where TOptions : class where TEntity : IEntity { const ulong countTo = 20UL; @@ -1461,15 +1440,15 @@ private async Task Generic_GivenTransactionAlreadyInserted_WhenQueryingByData_Th var transactionIds = GetSortedIds((int)countTo); var entityIds = GetSortedIds((int)countTo); + var agentSignature = new UnknownAgentSignature(new Dictionary()); + + var commands = new object[] { new DoNothing() }; + for (var i = 1UL; i <= countTo; i++) { var currentTransactionId = transactionIds[i - 1]; var currentEntityId = entityIds[i - 1]; - var agentSignature = new CounterAgentSignature(i); - - var commands = new object[] { new Count(i) }; - var leases = new[] { new CountLease(i) }; var tags = new[] { new CountTag(i) }; @@ -1484,19 +1463,17 @@ private async Task Generic_GivenTransactionAlreadyInserted_WhenQueryingByData_Th transactions.Add(transaction); } - var query = new CountQuery(gte, lte); + var options = serviceScope.ServiceProvider + .GetRequiredService>() + .Create("Count"); + + var query = new CountQuery(gte, lte, options); await InsertTransactions(serviceScope, transactions); - await TestGetTransactionIds(serviceScope, query as IAgentSignatureQuery, expectedObjects); - await TestGetTransactionIds(serviceScope, query as ICommandQuery, expectedObjects); await TestGetTransactionIds(serviceScope, query as ILeaseQuery, expectedObjects); await TestGetTransactionIds(serviceScope, query as ITagQuery, expectedObjects); - await TestGetEntityIds(serviceScope, query as IAgentSignatureQuery, expectedObjects); - await TestGetEntityIds(serviceScope, query as ICommandQuery, expectedObjects); await TestGetEntityIds(serviceScope, query as ILeaseQuery, expectedObjects); await TestGetEntityIds(serviceScope, query as ITagQuery, expectedObjects); - await TestGetAgentSignatures(serviceScope, query, expectedObjects); - await TestGetCommands(serviceScope, query, expectedObjects); await TestGetLeases(serviceScope, query, expectedObjects); await TestGetTags(serviceScope, query, expectedObjects); } @@ -1725,7 +1702,7 @@ public Task GivenTransactionAlreadyInserted_WhenQueryingByData_ThenReturnExpecte { return RunGenericTestAsync ( - new[] { entityAdder.EntityType }, + new[] { transactionsAdder.QueryOptionsType, entityAdder.EntityType }, new object?[] { transactionsAdder, entityAdder } ); } diff --git a/test/EntityDb.Common.Tests/Transactions/TryCatchTransactionRepositoryTests.cs b/test/EntityDb.Common.Tests/Transactions/TryCatchTransactionRepositoryTests.cs index f24f8f6e..8b2a7810 100644 --- a/test/EntityDb.Common.Tests/Transactions/TryCatchTransactionRepositoryTests.cs +++ b/test/EntityDb.Common.Tests/Transactions/TryCatchTransactionRepositoryTests.cs @@ -1,7 +1,4 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using EntityDb.Abstractions.Queries; +using EntityDb.Abstractions.Queries; using EntityDb.Abstractions.Transactions; using EntityDb.Common.Transactions; using Microsoft.Extensions.Logging; @@ -27,65 +24,62 @@ public async Task GivenRepositoryAlwaysThrows_WhenExecutingAnyMethod_ThenExcepti var transactionRepositoryMock = new Mock(MockBehavior.Strict); transactionRepositoryMock - .Setup(repository => - repository.GetTransactionIds(It.IsAny(), It.IsAny())) - .ThrowsAsync(new NotImplementedException()); + .Setup(repository => repository.EnumerateTransactionIds(It.IsAny(), It.IsAny())) + .Throws(new NotImplementedException()); transactionRepositoryMock - .Setup(repository => repository.GetTransactionIds(It.IsAny(), It.IsAny())) - .ThrowsAsync(new NotImplementedException()); + .Setup(repository => repository.EnumerateTransactionIds(It.IsAny(), It.IsAny())) + .Throws(new NotImplementedException()); transactionRepositoryMock - .Setup(repository => repository.GetTransactionIds(It.IsAny(), It.IsAny())) - .ThrowsAsync(new NotImplementedException()); + .Setup(repository => repository.EnumerateTransactionIds(It.IsAny(), It.IsAny())) + .Throws(new NotImplementedException()); transactionRepositoryMock - .Setup(repository => repository.GetTransactionIds(It.IsAny(), It.IsAny())) - .ThrowsAsync(new NotImplementedException()); + .Setup(repository => repository.EnumerateTransactionIds(It.IsAny(), It.IsAny())) + .Throws(new NotImplementedException()); transactionRepositoryMock - .Setup(repository => - repository.GetEntityIds(It.IsAny(), It.IsAny())) - .ThrowsAsync(new NotImplementedException()); + .Setup(repository => repository.EnumerateEntityIds(It.IsAny(), It.IsAny())) + .Throws(new NotImplementedException()); transactionRepositoryMock - .Setup(repository => repository.GetEntityIds(It.IsAny(), It.IsAny())) - .ThrowsAsync(new NotImplementedException()); + .Setup(repository => repository.EnumerateEntityIds(It.IsAny(), It.IsAny())) + .Throws(new NotImplementedException()); transactionRepositoryMock - .Setup(repository => repository.GetEntityIds(It.IsAny(), It.IsAny())) - .ThrowsAsync(new NotImplementedException()); + .Setup(repository => repository.EnumerateEntityIds(It.IsAny(), It.IsAny())) + .Throws(new NotImplementedException()); transactionRepositoryMock - .Setup(repository => repository.GetEntityIds(It.IsAny(), It.IsAny())) - .ThrowsAsync(new NotImplementedException()); + .Setup(repository => repository.EnumerateEntityIds(It.IsAny(), It.IsAny())) + .Throws(new NotImplementedException()); transactionRepositoryMock - .Setup(repository => - repository.GetAgentSignatures(It.IsAny(), It.IsAny())) - .ThrowsAsync(new NotImplementedException()); + .Setup(repository => repository.EnumerateAgentSignatures(It.IsAny(), It.IsAny())) + .Throws(new NotImplementedException()); transactionRepositoryMock - .Setup(repository => repository.GetCommands(It.IsAny(), It.IsAny())) - .ThrowsAsync(new NotImplementedException()); + .Setup(repository => repository.EnumerateCommands(It.IsAny(), It.IsAny())) + .Throws(new NotImplementedException()); transactionRepositoryMock - .Setup(repository => repository.GetLeases(It.IsAny(), It.IsAny())) - .ThrowsAsync(new NotImplementedException()); + .Setup(repository => repository.EnumerateLeases(It.IsAny(), It.IsAny())) + .Throws(new NotImplementedException()); transactionRepositoryMock - .Setup(repository => repository.GetTags(It.IsAny(), It.IsAny())) - .ThrowsAsync(new NotImplementedException()); + .Setup(repository => repository.EnumerateTags(It.IsAny(), It.IsAny())) + .Throws(new NotImplementedException()); transactionRepositoryMock .Setup(repository => - repository.GetAnnotatedAgentSignatures(It.IsAny(), It.IsAny())) - .ThrowsAsync(new NotImplementedException()); + repository.EnumerateAnnotatedAgentSignatures(It.IsAny(), It.IsAny())) + .Throws(new NotImplementedException()); transactionRepositoryMock .Setup(repository => - repository.GetAnnotatedCommands(It.IsAny(), It.IsAny())) - .ThrowsAsync(new NotImplementedException()); + repository.EnumerateAnnotatedCommands(It.IsAny(), It.IsAny())) + .Throws(new NotImplementedException()); transactionRepositoryMock .Setup(repository => repository.PutTransaction(It.IsAny(), It.IsAny())) @@ -97,22 +91,33 @@ public async Task GivenRepositoryAlwaysThrows_WhenExecutingAnyMethod_ThenExcepti // ACT var transactionIdsFromAgentSignatureQuery = - await tryCatchTransactionRepository.GetTransactionIds(default(IAgentSignatureQuery)!); + await tryCatchTransactionRepository.EnumerateTransactionIds(default(IAgentSignatureQuery)!).ToArrayAsync(); var transactionIdsFromCommandQuery = - await tryCatchTransactionRepository.GetTransactionIds(default(ICommandQuery)!); - var transactionIdsFromLeaseQuery = await tryCatchTransactionRepository.GetTransactionIds(default(ILeaseQuery)!); - var transactionIdsFromTagQuery = await tryCatchTransactionRepository.GetTransactionIds(default(ITagQuery)!); + await tryCatchTransactionRepository.EnumerateTransactionIds(default(ICommandQuery)!).ToArrayAsync(); + var transactionIdsFromLeaseQuery = + await tryCatchTransactionRepository.EnumerateTransactionIds(default(ILeaseQuery)!).ToArrayAsync(); + var transactionIdsFromTagQuery = + await tryCatchTransactionRepository.EnumerateTransactionIds(default(ITagQuery)!).ToArrayAsync(); var entityIdsFromAgentSignatureQuery = - await tryCatchTransactionRepository.GetEntityIds(default(IAgentSignatureQuery)!); - var entityIdsFromCommandQuery = await tryCatchTransactionRepository.GetEntityIds(default(ICommandQuery)!); - var entityIdsFromLeaseQuery = await tryCatchTransactionRepository.GetEntityIds(default(ILeaseQuery)!); - var entityIdsFromTagQuery = await tryCatchTransactionRepository.GetEntityIds(default(ITagQuery)!); - var agentSignatures = await tryCatchTransactionRepository.GetAgentSignatures(default!); - var commands = await tryCatchTransactionRepository.GetCommands(default!); - var leases = await tryCatchTransactionRepository.GetLeases(default!); - var tags = await tryCatchTransactionRepository.GetTags(default!); - var annotatedCommands = await tryCatchTransactionRepository.GetAnnotatedCommands(default!); - var inserted = await tryCatchTransactionRepository.PutTransaction(default!); + await tryCatchTransactionRepository.EnumerateEntityIds(default(IAgentSignatureQuery)!).ToArrayAsync(); + var entityIdsFromCommandQuery = + await tryCatchTransactionRepository.EnumerateEntityIds(default(ICommandQuery)!).ToArrayAsync(); + var entityIdsFromLeaseQuery = + await tryCatchTransactionRepository.EnumerateEntityIds(default(ILeaseQuery)!).ToArrayAsync(); + var entityIdsFromTagQuery = + await tryCatchTransactionRepository.EnumerateEntityIds(default(ITagQuery)!).ToArrayAsync(); + var agentSignatures = + await tryCatchTransactionRepository.EnumerateAgentSignatures(default!).ToArrayAsync(); + var commands = + await tryCatchTransactionRepository.EnumerateCommands(default!).ToArrayAsync(); + var leases = + await tryCatchTransactionRepository.EnumerateLeases(default!).ToArrayAsync(); + var tags = + await tryCatchTransactionRepository.EnumerateTags(default!).ToArrayAsync(); + var annotatedCommands = + await tryCatchTransactionRepository.EnumerateAnnotatedCommands(default!).ToArrayAsync(); + var inserted = + await tryCatchTransactionRepository.PutTransaction(default!); // ASSERT @@ -130,7 +135,6 @@ public async Task GivenRepositoryAlwaysThrows_WhenExecutingAnyMethod_ThenExcepti tags.ShouldBeEmpty(); annotatedCommands.ShouldBeEmpty(); inserted.ShouldBeFalse(); - loggerVerifier.Invoke(Times.Exactly(14)); } } \ No newline at end of file diff --git a/test/EntityDb.Common.Tests/TypeResolvers/DefaultTypeResolverTests.cs b/test/EntityDb.Common.Tests/TypeResolvers/DefaultTypeResolverTests.cs index 4b586327..4c33e266 100644 --- a/test/EntityDb.Common.Tests/TypeResolvers/DefaultTypeResolverTests.cs +++ b/test/EntityDb.Common.Tests/TypeResolvers/DefaultTypeResolverTests.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; -using System.IO; -using EntityDb.Common.Envelopes; +using EntityDb.Common.Envelopes; using EntityDb.Common.TypeResolvers; using Shouldly; using Xunit; diff --git a/test/EntityDb.Common.Tests/TypeResolvers/LifoTypeResolverTests.cs b/test/EntityDb.Common.Tests/TypeResolvers/LifoTypeResolverTests.cs index 65adb01d..72684d4e 100644 --- a/test/EntityDb.Common.Tests/TypeResolvers/LifoTypeResolverTests.cs +++ b/test/EntityDb.Common.Tests/TypeResolvers/LifoTypeResolverTests.cs @@ -1,5 +1,4 @@ -using System; -using EntityDb.Common.Envelopes; +using EntityDb.Common.Envelopes; using EntityDb.Common.Exceptions; using EntityDb.Common.Extensions; using EntityDb.Common.TypeResolvers; diff --git a/test/EntityDb.Common.Tests/TypeResolvers/MemberInfoNameTypeResolverTests.cs b/test/EntityDb.Common.Tests/TypeResolvers/MemberInfoNameTypeResolverTests.cs index c1600396..d06c6b4a 100644 --- a/test/EntityDb.Common.Tests/TypeResolvers/MemberInfoNameTypeResolverTests.cs +++ b/test/EntityDb.Common.Tests/TypeResolvers/MemberInfoNameTypeResolverTests.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using EntityDb.Common.Envelopes; +using EntityDb.Common.Envelopes; using EntityDb.Common.TypeResolvers; using Shouldly; using Xunit; diff --git a/test/EntityDb.Common.Tests/packages.lock.json b/test/EntityDb.Common.Tests/packages.lock.json index fc8d054a..5c095426 100644 --- a/test/EntityDb.Common.Tests/packages.lock.json +++ b/test/EntityDb.Common.Tests/packages.lock.json @@ -4,9 +4,9 @@ "net6.0": { "Bogus": { "type": "Direct", - "requested": "[34.0.1, )", - "resolved": "34.0.1", - "contentHash": "49iq7QrD0wb7V4/FcK8p3dWdJxNUbojaqK9L6KRvdikIuRjt38EsNp7QXICcYdbYw01K8BHUdxlnTNn/YX3qDA==" + "requested": "[34.0.2, )", + "resolved": "34.0.2", + "contentHash": "2KQAuMn3fLAQ2r6jeiffZnpv0bi3GCW3iRB2v1KeHIEBu8MNTh9dBlLTZwGvM0pr+9doKkU8L5JgCURmTmT88A==" }, "coverlet.collector": { "type": "Direct", @@ -16,22 +16,21 @@ }, "Microsoft.NET.Test.Sdk": { "type": "Direct", - "requested": "[17.0.0, )", - "resolved": "17.0.0", - "contentHash": "fJcnMY3jX1MzJvhGvUWauRhU5eQsOaHdwlrcnI3NabBhbi8WLAkMFI8d0YnewA/+b9q/U7vbhp8Xmh1vJ05FYQ==", + "requested": "[17.2.0, )", + "resolved": "17.2.0", + "contentHash": "kYmkDYbcDd+jNvmMH4TMtgHjsUYbIsWENM2VcjB0X7TawXbehL5I8OIsu2TgFS/nQCgZE94InrqMxrm7WDy+Lw==", "dependencies": { - "Microsoft.CodeCoverage": "17.0.0", - "Microsoft.TestPlatform.TestHost": "17.0.0" + "Microsoft.CodeCoverage": "17.2.0", + "Microsoft.TestPlatform.TestHost": "17.2.0" } }, "Moq": { "type": "Direct", - "requested": "[4.18.1, )", - "resolved": "4.18.1", - "contentHash": "MmZIKNyvn8VrivSaqA8tqy5DmwUievC9zsuNTrcb00oY4IeGq6fXT5BQK329lZ05/tyi5vp30AWe9fl0d2PZQg==", + "requested": "[4.18.2, )", + "resolved": "4.18.2", + "contentHash": "SjxKYS5nX6prcaT8ZjbkONh3vnh0Rxru09+gQ1a07v4TM530Oe/jq3Q4dOZPfo1wq0LYmTgLOZKrqRfEx4auPw==", "dependencies": { - "Castle.Core": "5.0.0", - "System.Threading.Tasks.Extensions": "4.5.4" + "Castle.Core": "5.1.0" } }, "Shouldly": { @@ -46,22 +45,44 @@ "System.Memory": "4.5.4" } }, + "System.Linq.Async": { + "type": "Direct", + "requested": "[6.0.1, )", + "resolved": "6.0.1", + "contentHash": "0YhHcaroWpQ9UCot3Pizah7ryAzQhNvobLMSxeDIGmnXfkQn8u5owvpOH0K6EVB+z9L7u6Cc4W17Br/+jyttEQ==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "6.0.0" + } + }, + "Testcontainers": { + "type": "Direct", + "requested": "[2.1.0, )", + "resolved": "2.1.0", + "contentHash": "ESpfTlnntNJfPoQ2gg/lNt2S+SuFAI7XYISfNWWKrroVOuJKGq/HsXQVA9Yj/n+fQ8TgpbMyGGiwZGxkbbVAKA==", + "dependencies": { + "Docker.DotNet": "3.125.10", + "Microsoft.Bcl.AsyncInterfaces": "1.1.1", + "Microsoft.Extensions.Logging.Abstractions": "3.1.26", + "SharpZipLib": "1.3.3", + "System.Text.Json": "4.7.2" + } + }, "xunit": { "type": "Direct", - "requested": "[2.4.1, )", - "resolved": "2.4.1", - "contentHash": "XNR3Yz9QTtec16O0aKcO6+baVNpXmOnPUxDkCY97J+8krUYxPvXT1szYYEUdKk4sB8GOI2YbAjRIOm8ZnXRfzQ==", + "requested": "[2.4.2, )", + "resolved": "2.4.2", + "contentHash": "6Mj73Ont3zj2CJuoykVJfE0ZmRwn7C+pTuRP8c4bnaaTFjwNG6tGe0prJ1yIbMe9AHrpDys63ctWacSsFJWK/w==", "dependencies": { - "xunit.analyzers": "0.10.0", - "xunit.assert": "[2.4.1]", - "xunit.core": "[2.4.1]" + "xunit.analyzers": "1.0.0", + "xunit.assert": "2.4.2", + "xunit.core": "[2.4.2]" } }, "Xunit.DependencyInjection": { "type": "Direct", - "requested": "[8.3.0, )", - "resolved": "8.3.0", - "contentHash": "uh4rHDT7IBpDB18zZWvP+jf7nbUYsGb71mHkeatNu9EvfTlY5MvtKGANBPwMEuxvnRhgypMSa14RhwunSvH5Ww==", + "requested": "[8.5.0, )", + "resolved": "8.5.0", + "contentHash": "OnSFB9x3MaXYFq9VFjdqoHgjOOjBOUxYFNkiQ3OXVe7I6r/KGs4yHJ3FAqZwddjNgKeRX1PEwiDWnDJOuonECQ==", "dependencies": { "Microsoft.Bcl.AsyncInterfaces": "1.0.0", "Microsoft.Extensions.Hosting": "2.1.0", @@ -71,23 +92,23 @@ }, "Xunit.DependencyInjection.Logging": { "type": "Direct", - "requested": "[8.0.0, )", - "resolved": "8.0.0", - "contentHash": "EfFGSxOGdu5k63+LBiPmG4rZ6kgTJF0WRES2MUriJ0LeLPD+0WJDNVjitx338O89ctt70gJ+JT9ogX4/74Esbg==", + "requested": "[8.0.1, )", + "resolved": "8.0.1", + "contentHash": "SXsc9Cp9LrpH3F9+35CbtCv0zuBw8491t3o5rK1/TVYeuwzVVR2h60/uGRYIs2GyVcKNRG7hOH8MbjPaap1sHQ==", "dependencies": { - "Xunit.DependencyInjection": "8.0.0" + "Xunit.DependencyInjection": "8.4.1" } }, "xunit.runner.visualstudio": { "type": "Direct", - "requested": "[2.4.3, )", - "resolved": "2.4.3", - "contentHash": "kZZSmOmKA8OBlAJaquPXnJJLM9RwQ27H7BMVqfMLUcTi9xHinWGJiWksa3D4NEtz0wZ/nxd2mogObvBgJKCRhQ==" + "requested": "[2.4.5, )", + "resolved": "2.4.5", + "contentHash": "OwHamvBdUKgqsXfBzWiCW/O98BTx81UKzx2bieIOQI7CZFE5NEQZGi8PBQGIKawDW96xeRffiNf20SjfC0x9hw==" }, "Castle.Core": { "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "edc8jjyXqzzy8jFdhs36FZdwmlDDTgqPb2Zy1Q5F/f2uAc88bu/VS/0Tpvgupmpl9zJOvOo5ZizVANb0ltN1NQ==", + "resolved": "5.1.0", + "contentHash": "31UJpTHOiWq95CDOHazE3Ub/hE/PydNWsJMwnEVTqFFP4WhAugwpaVGxzOxKgNeSUUeqS2W6lxV+q7u1pAOfXg==", "dependencies": { "System.Diagnostics.EventLog": "6.0.0" } @@ -109,6 +130,16 @@ "Microsoft.Win32.Registry": "5.0.0" } }, + "Docker.DotNet": { + "type": "Transitive", + "resolved": "3.125.10", + "contentHash": "sKu8AFiRPao1IqYPUT2mAxT0c7F+dgEfOonuVfgn5FYdHccHdL9Ge4Jsem0KHlxYzqE6QpOFDt1hR/J1XzqogQ==", + "dependencies": { + "Newtonsoft.Json": "13.0.1", + "System.Buffers": "4.5.1", + "System.Threading.Tasks.Extensions": "4.5.4" + } + }, "EmptyFiles": { "type": "Transitive", "resolved": "2.3.3", @@ -116,13 +147,13 @@ }, "Microsoft.Bcl.AsyncInterfaces": { "type": "Transitive", - "resolved": "1.0.0", - "contentHash": "K63Y4hORbBcKLWH5wnKgzyn7TOfYzevIEwIedQHBIkmkEBA9SCqgvom+XTuE+fAFGvINGkhFItaZ2dvMGdT5iw==" + "resolved": "6.0.0", + "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==" }, "Microsoft.CodeCoverage": { "type": "Transitive", - "resolved": "17.0.0", - "contentHash": "+B+09FPYBtf+cXfZOPIgpnP5mzLq5QdlBo+JEFy9CdqBaWHWE/YMY0Mos9uDsZhcgFegJm9GigAgMyqBZyfq+Q==" + "resolved": "17.2.0", + "contentHash": "MsKhJmwIfHxNDbTIlgQy29UpWSWPpbZOQPhQ7xalRy+ABnl8/neFHZGzSP3XlpW2dKAXHTFrtIcKzW/kopY2Bg==" }, "Microsoft.CSharp": { "type": "Transitive", @@ -224,8 +255,8 @@ }, "Microsoft.Extensions.Logging.Abstractions": { "type": "Transitive", - "resolved": "2.1.0", - "contentHash": "GfD2VtvN9z1W+m6pZZe98yh9VWTSdNY2dZSxtca9uFIY6aBI6twvskMvLO/ktClBOTQmAov/7Em+IWFlHepa0A==" + "resolved": "3.1.26", + "contentHash": "sCDtgEvfq0UhK6k9N7qCqvIsEud0T0eVu4UEW5G7urctFxRA8UUlcyrfFHH/k0tkEplZAv4EN8Xbj8j7BQNPhA==" }, "Microsoft.Extensions.Options": { "type": "Transitive", @@ -257,19 +288,19 @@ }, "Microsoft.TestPlatform.ObjectModel": { "type": "Transitive", - "resolved": "17.0.0", - "contentHash": "WMugCdPkA8U/BsSRc+3RN+DXcaYSDvp/s0MofVld08iF1O5fek4iKecygk6NruNf1rgJsv4LK71mrwbyeqhzHA==", + "resolved": "17.2.0", + "contentHash": "7j1KYDHLhU98XnCEbECMncXLydI9fNiFLcFsiBsP3lV6EkHOaj5kTPAWHYkKnPGRC9TbZUboSQq8rWI4dTQsxg==", "dependencies": { - "NuGet.Frameworks": "5.0.0", + "NuGet.Frameworks": "5.11.0", "System.Reflection.Metadata": "1.6.0" } }, "Microsoft.TestPlatform.TestHost": { "type": "Transitive", - "resolved": "17.0.0", - "contentHash": "xkKFzm0hylHF0SlDj78ACYMJC/i8fQ3i16sDDNYoKnjTsstGSQfuSBJ+QT4nqRXk/fOiYTh+iY0KIX5N7HTLuQ==", + "resolved": "17.2.0", + "contentHash": "bI67J+hers241h7eD2eecS02p9CbKcQDIeoRvO4FgMlTWg2ZTzc0D3uWLYr5U+K5x9O1pNmyMoMDbYIeWY/TWw==", "dependencies": { - "Microsoft.TestPlatform.ObjectModel": "17.0.0", + "Microsoft.TestPlatform.ObjectModel": "17.2.0", "Newtonsoft.Json": "9.0.1" } }, @@ -361,38 +392,38 @@ }, "MongoDB.Bson": { "type": "Transitive", - "resolved": "2.16.1", - "contentHash": "d647KTPQ7hWqJmvCg80iiVdm239llaUwMyIeRF/0zKpN+ddRWh9jT/g6R6WQrmi4qd7yodvv/Jn0rpEqh4QN8g==", + "resolved": "2.17.1", + "contentHash": "IBr5w6ygeUCTobiS4J2UlYeIsnjSJvOOf31g60EkRa3NIeyrYs7Y51HeOvJ8r6NPcKv1hLj8xwoop6hDTetAdA==", "dependencies": { "System.Runtime.CompilerServices.Unsafe": "5.0.0" } }, "MongoDB.Driver": { "type": "Transitive", - "resolved": "2.16.1", - "contentHash": "LqDWfRG7gM1tZKcG9Q/vuQGYF5GsBuxUF5KcOgvWrE6P7pSkOSL9xGZ7ABZ6XRVECGEQs+N6GyU1E4ViI4lh+g==", + "resolved": "2.17.1", + "contentHash": "A5Yvm3RUdkSYnvKWVb/bZfvhzG+L+t0n80JuUXf0p2QG1TbtqHE9hX/FBK+BoF7sw9rzUTw8VHYeqX5rT0rxdA==", "dependencies": { - "MongoDB.Bson": "2.16.1", - "MongoDB.Driver.Core": "2.16.1", - "MongoDB.Libmongocrypt": "1.5.3" + "MongoDB.Bson": "2.17.1", + "MongoDB.Driver.Core": "2.17.1", + "MongoDB.Libmongocrypt": "1.5.5" } }, "MongoDB.Driver.Core": { "type": "Transitive", - "resolved": "2.16.1", - "contentHash": "oJZnXHnAyTd/haHYdbfKMRmPEZ1fFrndv8xhorHeTkUDeGgsPA89vpGMHcjppUyHMYBpLgHbn6GoMkleHKsTHg==", + "resolved": "2.17.1", + "contentHash": "lfuuQvCXcco6mG096PL8xRO+dBdHsDTR3DiYfK/ICHgFlL5RfKlBuE0xClEGKtaZ4Spe28/fF/GUcrrA/yfoAQ==", "dependencies": { "DnsClient": "1.6.1", - "MongoDB.Bson": "2.16.1", - "MongoDB.Libmongocrypt": "1.5.3", + "MongoDB.Bson": "2.17.1", + "MongoDB.Libmongocrypt": "1.5.5", "SharpCompress": "0.30.1", "System.Buffers": "4.5.1" } }, "MongoDB.Libmongocrypt": { "type": "Transitive", - "resolved": "1.5.3", - "contentHash": "OWWxuyuxbjAmOLPoaoUEYnIW4F7qexS6XYOdu6absxyGAqLBWEY+M4WY2Y0km2UUG1+QOPdebpb/7cg5BIEbdw==" + "resolved": "1.5.5", + "contentHash": "0DV4l2PjXirSJHD/b+LpOK3IfUDvkbpvvZBM2w1aYL6E/4vbhfyr/FP5laDNx2zRylqN1hIZO+EL7NgO/5GpVg==" }, "NETStandard.Library": { "type": "Transitive", @@ -447,37 +478,21 @@ }, "Newtonsoft.Json": { "type": "Transitive", - "resolved": "9.0.1", - "contentHash": "U82mHQSKaIk+lpSVCbWYKNavmNH1i5xrExDEquU1i6I5pV6UMOqRnJRSlKO3cMPfcpp0RgDY+8jUXHdQ4IfXvw==", - "dependencies": { - "Microsoft.CSharp": "4.0.1", - "System.Collections": "4.0.11", - "System.Diagnostics.Debug": "4.0.11", - "System.Dynamic.Runtime": "4.0.11", - "System.Globalization": "4.0.11", - "System.IO": "4.1.0", - "System.Linq": "4.1.0", - "System.Linq.Expressions": "4.1.0", - "System.ObjectModel": "4.0.12", - "System.Reflection": "4.1.0", - "System.Reflection.Extensions": "4.0.1", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0", - "System.Runtime.Extensions": "4.1.0", - "System.Runtime.Serialization.Primitives": "4.1.1", - "System.Text.Encoding": "4.0.11", - "System.Text.Encoding.Extensions": "4.0.11", - "System.Text.RegularExpressions": "4.1.0", - "System.Threading": "4.0.11", - "System.Threading.Tasks": "4.0.11", - "System.Xml.ReaderWriter": "4.0.11", - "System.Xml.XDocument": "4.0.11" + "resolved": "13.0.1", + "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==" + }, + "Npgsql": { + "type": "Transitive", + "resolved": "6.0.6", + "contentHash": "IIwnoJp0sFkhAydT/KKe/0NhlJKhYPIrXSE95AuU/2dqHNI9alxvjClJSGL+QE8NGqq1SFn+NenxVtm/JYsrJg==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0" } }, "NuGet.Frameworks": { "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "c5JVjuVAm4f7E9Vj+v09Z9s2ZsqFDjBpcsyS3M9xRo0bEdm/LVZSzLxxNvfvAwRiiE8nwe1h2G4OwiwlzFKXlA==" + "resolved": "5.11.0", + "contentHash": "eaiXkUjC4NPcquGWzAGMXjuxvLwc6XGKMptSyOGQeT0X70BUZObuybJFZLA0OfTdueLd3US23NBPTBb6iF3V1Q==" }, "Pipelines.Sockets.Unofficial": { "type": "Transitive", @@ -655,6 +670,11 @@ "resolved": "0.30.1", "contentHash": "XqD4TpfyYGa7QTPzaGlMVbcecKnXy4YmYLDWrU+JIj7IuRNl7DH2END+Ll7ekWIY8o3dAMWLFDE1xdhfIWD1nw==" }, + "SharpZipLib": { + "type": "Transitive", + "resolved": "1.3.3", + "contentHash": "N8+hwhsKZm25tDJfWpBSW7EGhH/R7EMuiX+KJ4C4u+fCWVc1lJ5zg1u3S1RPPVYgTqhx/C3hxrqUpi6RwK5+Tg==" + }, "StackExchange.Redis": { "type": "Transitive", "resolved": "2.6.48", @@ -888,28 +908,6 @@ "Microsoft.Win32.SystemEvents": "5.0.0" } }, - "System.Dynamic.Runtime": { - "type": "Transitive", - "resolved": "4.0.11", - "contentHash": "db34f6LHYM0U0JpE+sOmjar27BnqTVkbLJhgfwMpTdgTigG/Hna3m2MYVwnFzGGKnEJk2UXFuoVTr8WUbU91/A==", - "dependencies": { - "System.Collections": "4.0.11", - "System.Diagnostics.Debug": "4.0.11", - "System.Globalization": "4.0.11", - "System.Linq": "4.1.0", - "System.Linq.Expressions": "4.1.0", - "System.ObjectModel": "4.0.12", - "System.Reflection": "4.1.0", - "System.Reflection.Emit": "4.0.1", - "System.Reflection.Emit.ILGeneration": "4.0.1", - "System.Reflection.Primitives": "4.0.1", - "System.Reflection.TypeExtensions": "4.1.0", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0", - "System.Runtime.Extensions": "4.1.0", - "System.Threading": "4.0.11" - } - }, "System.Formats.Asn1": { "type": "Transitive", "resolved": "5.0.0", @@ -1353,15 +1351,6 @@ "System.Runtime.Extensions": "4.3.0" } }, - "System.Runtime.Serialization.Primitives": { - "type": "Transitive", - "resolved": "4.1.1", - "contentHash": "HZ6Du5QrTG8MNJbf4e4qMO3JRAkIboGT5Fk804uZtg3Gq516S7hAqTm2UZKUHa7/6HUGdVy3AqMQKbns06G/cg==", - "dependencies": { - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0" - } - }, "System.Security.AccessControl": { "type": "Transitive", "resolved": "5.0.0", @@ -1628,6 +1617,11 @@ "System.Text.Encoding": "4.3.0" } }, + "System.Text.Json": { + "type": "Transitive", + "resolved": "4.7.2", + "contentHash": "TcMd95wcrubm9nHvJEQs70rC0H/8omiSGGpU4FQ/ZA1URIqD4pjmFJh2Mfv1yH1eHgJDWTi2hMDXwTET+zOOyg==" + }, "System.Text.RegularExpressions": { "type": "Transitive", "resolved": "4.3.0", @@ -1735,30 +1729,30 @@ }, "xunit.analyzers": { "type": "Transitive", - "resolved": "0.10.0", - "contentHash": "4/IDFCJfIeg6bix9apmUtIMwvOsiwqdEexeO/R2D4GReIGPLIRODTpId/l4LRSrAJk9lEO3Zx1H0Zx6uohJDNg==" + "resolved": "1.0.0", + "contentHash": "BeO8hEgs/c8Ls2647fPfieMngncvf0D0xYNDfIO59MolxtCtVjFRd6SRc+7tj8VMqkVOuJcnc9eh4ngI2cAmLQ==" }, "xunit.assert": { "type": "Transitive", - "resolved": "2.4.1", - "contentHash": "O/Oe0BS5RmSsM+LQOb041TzuPo5MdH2Rov+qXGS37X+KFG1Hxz7kopYklM5+1Y+tRGeXrOx5+Xne1RuqLFQoyQ==", + "resolved": "2.4.2", + "contentHash": "pxJISOFjn2XTTi1mcDCkRZrTFb9OtRRCtx2kZFNF51GdReLr1ls2rnyxvAS4JO247K3aNtflvh5Q0346K5BROA==", "dependencies": { "NETStandard.Library": "1.6.1" } }, "xunit.core": { "type": "Transitive", - "resolved": "2.4.1", - "contentHash": "Zsj5OMU6JasNGERXZy8s72+pcheG6Q15atS5XpZXqAtULuyQiQ6XNnUsp1gyfC6WgqScqMvySiEHmHcOG6Eg0Q==", + "resolved": "2.4.2", + "contentHash": "KB4yGCxNqIVyekhJLXtKSEq6BaXVp/JO3mbGVE1hxypZTLEe7h+sTbAhpA+yZW2dPtXTuiW+C1B2oxxHEkrmOw==", "dependencies": { - "xunit.extensibility.core": "[2.4.1]", - "xunit.extensibility.execution": "[2.4.1]" + "xunit.extensibility.core": "[2.4.2]", + "xunit.extensibility.execution": "[2.4.2]" } }, "xunit.extensibility.core": { "type": "Transitive", - "resolved": "2.4.1", - "contentHash": "yKZKm/8QNZnBnGZFD9SewkllHBiK0DThybQD/G4PiAmQjKtEZyHi6ET70QPU9KtSMJGRYS6Syk7EyR2EVDU4Kg==", + "resolved": "2.4.2", + "contentHash": "W1BoXTIN1C6kpVSMw25huSet25ky6IAQUNovu3zGOGN/jWnbgSoTyCrlIhmXSg0tH5nEf8q7h3OjNHOjyu5PfA==", "dependencies": { "NETStandard.Library": "1.6.1", "xunit.abstractions": "2.0.3" @@ -1766,33 +1760,46 @@ }, "xunit.extensibility.execution": { "type": "Transitive", - "resolved": "2.4.1", - "contentHash": "7e/1jqBpcb7frLkB6XDrHCGXAbKN4Rtdb88epYxCSRQuZDRW8UtTfdTEVpdTl8s4T56e07hOBVd4G0OdCxIY2A==", + "resolved": "2.4.2", + "contentHash": "CZmgcKkwpyo8FlupZdWpJCryrAOWLh1FBPG6gmVZuPQkGQsim/oL4PcP4nfrC2hHgXUFtluvaJ0Sp9PQKUMNpg==", "dependencies": { "NETStandard.Library": "1.6.1", - "xunit.extensibility.core": "[2.4.1]" + "xunit.extensibility.core": "[2.4.2]" } }, "entitydb.abstractions": { - "type": "Project" + "type": "Project", + "dependencies": { + "System.Linq.Async": "6.0.1" + } }, "entitydb.common": { "type": "Project", "dependencies": { - "EntityDb.Abstractions": "1.0.0" + "EntityDb.Abstractions": "1.0.0", + "System.Linq.Async": "6.0.1" } }, "entitydb.inmemory": { "type": "Project", "dependencies": { - "EntityDb.Common": "1.0.0" + "EntityDb.Common": "1.0.0", + "System.Linq.Async": "6.0.1" + } + }, + "entitydb.json": { + "type": "Project", + "dependencies": { + "EntityDb.Common": "1.0.0", + "System.Linq.Async": "6.0.1" } }, "entitydb.mongodb": { "type": "Project", "dependencies": { "EntityDb.Common": "1.0.0", - "MongoDB.Driver": "2.16.1" + "MongoDB.Driver": "2.17.1", + "System.Linq.Async": "6.0.1" } }, "entitydb.mongodb.provisioner": { @@ -1800,14 +1807,42 @@ "dependencies": { "EntityDb.MongoDb": "1.0.0", "System.CommandLine": "2.0.0-beta4.22272.1", - "System.CommandLine.NamingConventionBinder": "2.0.0-beta4.22272.1" + "System.CommandLine.NamingConventionBinder": "2.0.0-beta4.22272.1", + "System.Linq.Async": "6.0.1" + } + }, + "entitydb.npgsql": { + "type": "Project", + "dependencies": { + "EntityDb.SqlDb": "1.0.0", + "Npgsql": "6.0.6", + "System.Linq.Async": "6.0.1" + } + }, + "entitydb.npgsql.provisioner": { + "type": "Project", + "dependencies": { + "EntityDb.Npgsql": "1.0.0", + "System.CommandLine": "2.0.0-beta4.22272.1", + "System.CommandLine.NamingConventionBinder": "2.0.0-beta4.22272.1", + "System.Linq.Async": "6.0.1" } }, "entitydb.redis": { "type": "Project", "dependencies": { "EntityDb.Common": "1.0.0", - "StackExchange.Redis": "2.6.48" + "EntityDb.Json": "1.0.0", + "StackExchange.Redis": "2.6.48", + "System.Linq.Async": "6.0.1" + } + }, + "entitydb.sqldb": { + "type": "Project", + "dependencies": { + "EntityDb.Common": "1.0.0", + "EntityDb.Json": "1.0.0", + "System.Linq.Async": "6.0.1" } } } diff --git a/test/EntityDb.MongoDb.Tests/Envelopes/BsonDocumentEnvelopeTests.cs b/test/EntityDb.MongoDb.Tests/Envelopes/BsonDocumentEnvelopeTests.cs index 52be4296..60be64cb 100644 --- a/test/EntityDb.MongoDb.Tests/Envelopes/BsonDocumentEnvelopeTests.cs +++ b/test/EntityDb.MongoDb.Tests/Envelopes/BsonDocumentEnvelopeTests.cs @@ -1,6 +1,4 @@ -using System; -using System.Text; -using EntityDb.Common.Envelopes; +using EntityDb.Common.Envelopes; using EntityDb.Common.Tests.Envelopes; using EntityDb.MongoDb.Envelopes; using EntityDb.MongoDb.Extensions; @@ -18,11 +16,9 @@ public BsonDocumentEnvelopeTests(IServiceProvider startupServiceProvider) : base { } - protected override byte[] GenerateCorruptedBytes() + protected override BsonDocument GenerateCorruptedSerializedData() { - const string invalidBson = "I AM A STRING VALUE, NOT BSON!"; - - return Encoding.UTF8.GetBytes(invalidBson); + return null!; } [Theory] @@ -47,10 +43,10 @@ public void GivenTypeDiscriminatorShouldBeRemovedOption_ThereBsonDocumentMatches var value = new TestRecord(true); - var bsonDocumentEnvelope = envelopeService.Deconstruct(value); + var bsonDocumentEnvelope = envelopeService.Serialize(value); var actualContainsTypeDiscriminatorProperty = - bsonDocumentEnvelope.Value.Contains(BsonDocumentEnvelopeService.TypeDiscriminatorPropertyName); + bsonDocumentEnvelope.GetElement("Value").Value.AsBsonDocument.Contains(MongoDbEnvelopeService.TypeDiscriminatorPropertyName); // ASSERT diff --git a/test/EntityDb.MongoDb.Tests/Rewriters/BsonDocumentRewriterTests.cs b/test/EntityDb.MongoDb.Tests/Rewriters/BsonDocumentRewriterTests.cs index 795b3a82..7793d5e1 100644 --- a/test/EntityDb.MongoDb.Tests/Rewriters/BsonDocumentRewriterTests.cs +++ b/test/EntityDb.MongoDb.Tests/Rewriters/BsonDocumentRewriterTests.cs @@ -1,6 +1,4 @@ -using System; -using System.Linq; -using System.Text.RegularExpressions; +using System.Text.RegularExpressions; using EntityDb.MongoDb.Rewriters; using MongoDB.Bson; using MongoDB.Bson.IO; diff --git a/test/EntityDb.MongoDb.Tests/Sessions/MongoSessionTests.cs b/test/EntityDb.MongoDb.Tests/Sessions/MongoSessionTests.cs index 9b1edae7..c1d593e6 100644 --- a/test/EntityDb.MongoDb.Tests/Sessions/MongoSessionTests.cs +++ b/test/EntityDb.MongoDb.Tests/Sessions/MongoSessionTests.cs @@ -1,6 +1,4 @@ -using System; -using System.Threading.Tasks; -using EntityDb.Common.Exceptions; +using EntityDb.Common.Exceptions; using EntityDb.Common.Tests; using EntityDb.MongoDb.Sessions; using Shouldly; diff --git a/test/EntityDb.MongoDb.Tests/packages.lock.json b/test/EntityDb.MongoDb.Tests/packages.lock.json index 4ae4e6a4..61c5e105 100644 --- a/test/EntityDb.MongoDb.Tests/packages.lock.json +++ b/test/EntityDb.MongoDb.Tests/packages.lock.json @@ -4,9 +4,9 @@ "net6.0": { "Bogus": { "type": "Direct", - "requested": "[34.0.1, )", - "resolved": "34.0.1", - "contentHash": "49iq7QrD0wb7V4/FcK8p3dWdJxNUbojaqK9L6KRvdikIuRjt38EsNp7QXICcYdbYw01K8BHUdxlnTNn/YX3qDA==" + "requested": "[34.0.2, )", + "resolved": "34.0.2", + "contentHash": "2KQAuMn3fLAQ2r6jeiffZnpv0bi3GCW3iRB2v1KeHIEBu8MNTh9dBlLTZwGvM0pr+9doKkU8L5JgCURmTmT88A==" }, "coverlet.collector": { "type": "Direct", @@ -16,22 +16,21 @@ }, "Microsoft.NET.Test.Sdk": { "type": "Direct", - "requested": "[17.0.0, )", - "resolved": "17.0.0", - "contentHash": "fJcnMY3jX1MzJvhGvUWauRhU5eQsOaHdwlrcnI3NabBhbi8WLAkMFI8d0YnewA/+b9q/U7vbhp8Xmh1vJ05FYQ==", + "requested": "[17.2.0, )", + "resolved": "17.2.0", + "contentHash": "kYmkDYbcDd+jNvmMH4TMtgHjsUYbIsWENM2VcjB0X7TawXbehL5I8OIsu2TgFS/nQCgZE94InrqMxrm7WDy+Lw==", "dependencies": { - "Microsoft.CodeCoverage": "17.0.0", - "Microsoft.TestPlatform.TestHost": "17.0.0" + "Microsoft.CodeCoverage": "17.2.0", + "Microsoft.TestPlatform.TestHost": "17.2.0" } }, "Moq": { "type": "Direct", - "requested": "[4.18.1, )", - "resolved": "4.18.1", - "contentHash": "MmZIKNyvn8VrivSaqA8tqy5DmwUievC9zsuNTrcb00oY4IeGq6fXT5BQK329lZ05/tyi5vp30AWe9fl0d2PZQg==", + "requested": "[4.18.2, )", + "resolved": "4.18.2", + "contentHash": "SjxKYS5nX6prcaT8ZjbkONh3vnh0Rxru09+gQ1a07v4TM530Oe/jq3Q4dOZPfo1wq0LYmTgLOZKrqRfEx4auPw==", "dependencies": { - "Castle.Core": "5.0.0", - "System.Threading.Tasks.Extensions": "4.5.4" + "Castle.Core": "5.1.0" } }, "Shouldly": { @@ -46,22 +45,31 @@ "System.Memory": "4.5.4" } }, + "System.Linq.Async": { + "type": "Direct", + "requested": "[6.0.1, )", + "resolved": "6.0.1", + "contentHash": "0YhHcaroWpQ9UCot3Pizah7ryAzQhNvobLMSxeDIGmnXfkQn8u5owvpOH0K6EVB+z9L7u6Cc4W17Br/+jyttEQ==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "6.0.0" + } + }, "xunit": { "type": "Direct", - "requested": "[2.4.1, )", - "resolved": "2.4.1", - "contentHash": "XNR3Yz9QTtec16O0aKcO6+baVNpXmOnPUxDkCY97J+8krUYxPvXT1szYYEUdKk4sB8GOI2YbAjRIOm8ZnXRfzQ==", + "requested": "[2.4.2, )", + "resolved": "2.4.2", + "contentHash": "6Mj73Ont3zj2CJuoykVJfE0ZmRwn7C+pTuRP8c4bnaaTFjwNG6tGe0prJ1yIbMe9AHrpDys63ctWacSsFJWK/w==", "dependencies": { - "xunit.analyzers": "0.10.0", - "xunit.assert": "[2.4.1]", - "xunit.core": "[2.4.1]" + "xunit.analyzers": "1.0.0", + "xunit.assert": "2.4.2", + "xunit.core": "[2.4.2]" } }, "Xunit.DependencyInjection": { "type": "Direct", - "requested": "[8.3.0, )", - "resolved": "8.3.0", - "contentHash": "uh4rHDT7IBpDB18zZWvP+jf7nbUYsGb71mHkeatNu9EvfTlY5MvtKGANBPwMEuxvnRhgypMSa14RhwunSvH5Ww==", + "requested": "[8.5.0, )", + "resolved": "8.5.0", + "contentHash": "OnSFB9x3MaXYFq9VFjdqoHgjOOjBOUxYFNkiQ3OXVe7I6r/KGs4yHJ3FAqZwddjNgKeRX1PEwiDWnDJOuonECQ==", "dependencies": { "Microsoft.Bcl.AsyncInterfaces": "1.0.0", "Microsoft.Extensions.Hosting": "2.1.0", @@ -71,23 +79,23 @@ }, "Xunit.DependencyInjection.Logging": { "type": "Direct", - "requested": "[8.0.0, )", - "resolved": "8.0.0", - "contentHash": "EfFGSxOGdu5k63+LBiPmG4rZ6kgTJF0WRES2MUriJ0LeLPD+0WJDNVjitx338O89ctt70gJ+JT9ogX4/74Esbg==", + "requested": "[8.0.1, )", + "resolved": "8.0.1", + "contentHash": "SXsc9Cp9LrpH3F9+35CbtCv0zuBw8491t3o5rK1/TVYeuwzVVR2h60/uGRYIs2GyVcKNRG7hOH8MbjPaap1sHQ==", "dependencies": { - "Xunit.DependencyInjection": "8.0.0" + "Xunit.DependencyInjection": "8.4.1" } }, "xunit.runner.visualstudio": { "type": "Direct", - "requested": "[2.4.3, )", - "resolved": "2.4.3", - "contentHash": "kZZSmOmKA8OBlAJaquPXnJJLM9RwQ27H7BMVqfMLUcTi9xHinWGJiWksa3D4NEtz0wZ/nxd2mogObvBgJKCRhQ==" + "requested": "[2.4.5, )", + "resolved": "2.4.5", + "contentHash": "OwHamvBdUKgqsXfBzWiCW/O98BTx81UKzx2bieIOQI7CZFE5NEQZGi8PBQGIKawDW96xeRffiNf20SjfC0x9hw==" }, "Castle.Core": { "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "edc8jjyXqzzy8jFdhs36FZdwmlDDTgqPb2Zy1Q5F/f2uAc88bu/VS/0Tpvgupmpl9zJOvOo5ZizVANb0ltN1NQ==", + "resolved": "5.1.0", + "contentHash": "31UJpTHOiWq95CDOHazE3Ub/hE/PydNWsJMwnEVTqFFP4WhAugwpaVGxzOxKgNeSUUeqS2W6lxV+q7u1pAOfXg==", "dependencies": { "System.Diagnostics.EventLog": "6.0.0" } @@ -109,6 +117,16 @@ "Microsoft.Win32.Registry": "5.0.0" } }, + "Docker.DotNet": { + "type": "Transitive", + "resolved": "3.125.10", + "contentHash": "sKu8AFiRPao1IqYPUT2mAxT0c7F+dgEfOonuVfgn5FYdHccHdL9Ge4Jsem0KHlxYzqE6QpOFDt1hR/J1XzqogQ==", + "dependencies": { + "Newtonsoft.Json": "13.0.1", + "System.Buffers": "4.5.1", + "System.Threading.Tasks.Extensions": "4.5.4" + } + }, "EmptyFiles": { "type": "Transitive", "resolved": "2.3.3", @@ -116,13 +134,13 @@ }, "Microsoft.Bcl.AsyncInterfaces": { "type": "Transitive", - "resolved": "1.0.0", - "contentHash": "K63Y4hORbBcKLWH5wnKgzyn7TOfYzevIEwIedQHBIkmkEBA9SCqgvom+XTuE+fAFGvINGkhFItaZ2dvMGdT5iw==" + "resolved": "6.0.0", + "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==" }, "Microsoft.CodeCoverage": { "type": "Transitive", - "resolved": "17.0.0", - "contentHash": "+B+09FPYBtf+cXfZOPIgpnP5mzLq5QdlBo+JEFy9CdqBaWHWE/YMY0Mos9uDsZhcgFegJm9GigAgMyqBZyfq+Q==" + "resolved": "17.2.0", + "contentHash": "MsKhJmwIfHxNDbTIlgQy29UpWSWPpbZOQPhQ7xalRy+ABnl8/neFHZGzSP3XlpW2dKAXHTFrtIcKzW/kopY2Bg==" }, "Microsoft.CSharp": { "type": "Transitive", @@ -224,8 +242,8 @@ }, "Microsoft.Extensions.Logging.Abstractions": { "type": "Transitive", - "resolved": "2.1.0", - "contentHash": "GfD2VtvN9z1W+m6pZZe98yh9VWTSdNY2dZSxtca9uFIY6aBI6twvskMvLO/ktClBOTQmAov/7Em+IWFlHepa0A==" + "resolved": "3.1.26", + "contentHash": "sCDtgEvfq0UhK6k9N7qCqvIsEud0T0eVu4UEW5G7urctFxRA8UUlcyrfFHH/k0tkEplZAv4EN8Xbj8j7BQNPhA==" }, "Microsoft.Extensions.Options": { "type": "Transitive", @@ -257,19 +275,19 @@ }, "Microsoft.TestPlatform.ObjectModel": { "type": "Transitive", - "resolved": "17.0.0", - "contentHash": "WMugCdPkA8U/BsSRc+3RN+DXcaYSDvp/s0MofVld08iF1O5fek4iKecygk6NruNf1rgJsv4LK71mrwbyeqhzHA==", + "resolved": "17.2.0", + "contentHash": "7j1KYDHLhU98XnCEbECMncXLydI9fNiFLcFsiBsP3lV6EkHOaj5kTPAWHYkKnPGRC9TbZUboSQq8rWI4dTQsxg==", "dependencies": { - "NuGet.Frameworks": "5.0.0", + "NuGet.Frameworks": "5.11.0", "System.Reflection.Metadata": "1.6.0" } }, "Microsoft.TestPlatform.TestHost": { "type": "Transitive", - "resolved": "17.0.0", - "contentHash": "xkKFzm0hylHF0SlDj78ACYMJC/i8fQ3i16sDDNYoKnjTsstGSQfuSBJ+QT4nqRXk/fOiYTh+iY0KIX5N7HTLuQ==", + "resolved": "17.2.0", + "contentHash": "bI67J+hers241h7eD2eecS02p9CbKcQDIeoRvO4FgMlTWg2ZTzc0D3uWLYr5U+K5x9O1pNmyMoMDbYIeWY/TWw==", "dependencies": { - "Microsoft.TestPlatform.ObjectModel": "17.0.0", + "Microsoft.TestPlatform.ObjectModel": "17.2.0", "Newtonsoft.Json": "9.0.1" } }, @@ -361,38 +379,38 @@ }, "MongoDB.Bson": { "type": "Transitive", - "resolved": "2.16.1", - "contentHash": "d647KTPQ7hWqJmvCg80iiVdm239llaUwMyIeRF/0zKpN+ddRWh9jT/g6R6WQrmi4qd7yodvv/Jn0rpEqh4QN8g==", + "resolved": "2.17.1", + "contentHash": "IBr5w6ygeUCTobiS4J2UlYeIsnjSJvOOf31g60EkRa3NIeyrYs7Y51HeOvJ8r6NPcKv1hLj8xwoop6hDTetAdA==", "dependencies": { "System.Runtime.CompilerServices.Unsafe": "5.0.0" } }, "MongoDB.Driver": { "type": "Transitive", - "resolved": "2.16.1", - "contentHash": "LqDWfRG7gM1tZKcG9Q/vuQGYF5GsBuxUF5KcOgvWrE6P7pSkOSL9xGZ7ABZ6XRVECGEQs+N6GyU1E4ViI4lh+g==", + "resolved": "2.17.1", + "contentHash": "A5Yvm3RUdkSYnvKWVb/bZfvhzG+L+t0n80JuUXf0p2QG1TbtqHE9hX/FBK+BoF7sw9rzUTw8VHYeqX5rT0rxdA==", "dependencies": { - "MongoDB.Bson": "2.16.1", - "MongoDB.Driver.Core": "2.16.1", - "MongoDB.Libmongocrypt": "1.5.3" + "MongoDB.Bson": "2.17.1", + "MongoDB.Driver.Core": "2.17.1", + "MongoDB.Libmongocrypt": "1.5.5" } }, "MongoDB.Driver.Core": { "type": "Transitive", - "resolved": "2.16.1", - "contentHash": "oJZnXHnAyTd/haHYdbfKMRmPEZ1fFrndv8xhorHeTkUDeGgsPA89vpGMHcjppUyHMYBpLgHbn6GoMkleHKsTHg==", + "resolved": "2.17.1", + "contentHash": "lfuuQvCXcco6mG096PL8xRO+dBdHsDTR3DiYfK/ICHgFlL5RfKlBuE0xClEGKtaZ4Spe28/fF/GUcrrA/yfoAQ==", "dependencies": { "DnsClient": "1.6.1", - "MongoDB.Bson": "2.16.1", - "MongoDB.Libmongocrypt": "1.5.3", + "MongoDB.Bson": "2.17.1", + "MongoDB.Libmongocrypt": "1.5.5", "SharpCompress": "0.30.1", "System.Buffers": "4.5.1" } }, "MongoDB.Libmongocrypt": { "type": "Transitive", - "resolved": "1.5.3", - "contentHash": "OWWxuyuxbjAmOLPoaoUEYnIW4F7qexS6XYOdu6absxyGAqLBWEY+M4WY2Y0km2UUG1+QOPdebpb/7cg5BIEbdw==" + "resolved": "1.5.5", + "contentHash": "0DV4l2PjXirSJHD/b+LpOK3IfUDvkbpvvZBM2w1aYL6E/4vbhfyr/FP5laDNx2zRylqN1hIZO+EL7NgO/5GpVg==" }, "NETStandard.Library": { "type": "Transitive", @@ -447,37 +465,21 @@ }, "Newtonsoft.Json": { "type": "Transitive", - "resolved": "9.0.1", - "contentHash": "U82mHQSKaIk+lpSVCbWYKNavmNH1i5xrExDEquU1i6I5pV6UMOqRnJRSlKO3cMPfcpp0RgDY+8jUXHdQ4IfXvw==", - "dependencies": { - "Microsoft.CSharp": "4.0.1", - "System.Collections": "4.0.11", - "System.Diagnostics.Debug": "4.0.11", - "System.Dynamic.Runtime": "4.0.11", - "System.Globalization": "4.0.11", - "System.IO": "4.1.0", - "System.Linq": "4.1.0", - "System.Linq.Expressions": "4.1.0", - "System.ObjectModel": "4.0.12", - "System.Reflection": "4.1.0", - "System.Reflection.Extensions": "4.0.1", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0", - "System.Runtime.Extensions": "4.1.0", - "System.Runtime.Serialization.Primitives": "4.1.1", - "System.Text.Encoding": "4.0.11", - "System.Text.Encoding.Extensions": "4.0.11", - "System.Text.RegularExpressions": "4.1.0", - "System.Threading": "4.0.11", - "System.Threading.Tasks": "4.0.11", - "System.Xml.ReaderWriter": "4.0.11", - "System.Xml.XDocument": "4.0.11" + "resolved": "13.0.1", + "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==" + }, + "Npgsql": { + "type": "Transitive", + "resolved": "6.0.6", + "contentHash": "IIwnoJp0sFkhAydT/KKe/0NhlJKhYPIrXSE95AuU/2dqHNI9alxvjClJSGL+QE8NGqq1SFn+NenxVtm/JYsrJg==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0" } }, "NuGet.Frameworks": { "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "c5JVjuVAm4f7E9Vj+v09Z9s2ZsqFDjBpcsyS3M9xRo0bEdm/LVZSzLxxNvfvAwRiiE8nwe1h2G4OwiwlzFKXlA==" + "resolved": "5.11.0", + "contentHash": "eaiXkUjC4NPcquGWzAGMXjuxvLwc6XGKMptSyOGQeT0X70BUZObuybJFZLA0OfTdueLd3US23NBPTBb6iF3V1Q==" }, "Pipelines.Sockets.Unofficial": { "type": "Transitive", @@ -655,6 +657,11 @@ "resolved": "0.30.1", "contentHash": "XqD4TpfyYGa7QTPzaGlMVbcecKnXy4YmYLDWrU+JIj7IuRNl7DH2END+Ll7ekWIY8o3dAMWLFDE1xdhfIWD1nw==" }, + "SharpZipLib": { + "type": "Transitive", + "resolved": "1.3.3", + "contentHash": "N8+hwhsKZm25tDJfWpBSW7EGhH/R7EMuiX+KJ4C4u+fCWVc1lJ5zg1u3S1RPPVYgTqhx/C3hxrqUpi6RwK5+Tg==" + }, "StackExchange.Redis": { "type": "Transitive", "resolved": "2.6.48", @@ -888,28 +895,6 @@ "Microsoft.Win32.SystemEvents": "5.0.0" } }, - "System.Dynamic.Runtime": { - "type": "Transitive", - "resolved": "4.0.11", - "contentHash": "db34f6LHYM0U0JpE+sOmjar27BnqTVkbLJhgfwMpTdgTigG/Hna3m2MYVwnFzGGKnEJk2UXFuoVTr8WUbU91/A==", - "dependencies": { - "System.Collections": "4.0.11", - "System.Diagnostics.Debug": "4.0.11", - "System.Globalization": "4.0.11", - "System.Linq": "4.1.0", - "System.Linq.Expressions": "4.1.0", - "System.ObjectModel": "4.0.12", - "System.Reflection": "4.1.0", - "System.Reflection.Emit": "4.0.1", - "System.Reflection.Emit.ILGeneration": "4.0.1", - "System.Reflection.Primitives": "4.0.1", - "System.Reflection.TypeExtensions": "4.1.0", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0", - "System.Runtime.Extensions": "4.1.0", - "System.Threading": "4.0.11" - } - }, "System.Formats.Asn1": { "type": "Transitive", "resolved": "5.0.0", @@ -1353,15 +1338,6 @@ "System.Runtime.Extensions": "4.3.0" } }, - "System.Runtime.Serialization.Primitives": { - "type": "Transitive", - "resolved": "4.1.1", - "contentHash": "HZ6Du5QrTG8MNJbf4e4qMO3JRAkIboGT5Fk804uZtg3Gq516S7hAqTm2UZKUHa7/6HUGdVy3AqMQKbns06G/cg==", - "dependencies": { - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0" - } - }, "System.Security.AccessControl": { "type": "Transitive", "resolved": "5.0.0", @@ -1628,6 +1604,11 @@ "System.Text.Encoding": "4.3.0" } }, + "System.Text.Json": { + "type": "Transitive", + "resolved": "4.7.2", + "contentHash": "TcMd95wcrubm9nHvJEQs70rC0H/8omiSGGpU4FQ/ZA1URIqD4pjmFJh2Mfv1yH1eHgJDWTi2hMDXwTET+zOOyg==" + }, "System.Text.RegularExpressions": { "type": "Transitive", "resolved": "4.3.0", @@ -1728,6 +1709,18 @@ "System.Xml.ReaderWriter": "4.3.0" } }, + "Testcontainers": { + "type": "Transitive", + "resolved": "2.1.0", + "contentHash": "ESpfTlnntNJfPoQ2gg/lNt2S+SuFAI7XYISfNWWKrroVOuJKGq/HsXQVA9Yj/n+fQ8TgpbMyGGiwZGxkbbVAKA==", + "dependencies": { + "Docker.DotNet": "3.125.10", + "Microsoft.Bcl.AsyncInterfaces": "1.1.1", + "Microsoft.Extensions.Logging.Abstractions": "3.1.26", + "SharpZipLib": "1.3.3", + "System.Text.Json": "4.7.2" + } + }, "xunit.abstractions": { "type": "Transitive", "resolved": "2.0.3", @@ -1735,30 +1728,30 @@ }, "xunit.analyzers": { "type": "Transitive", - "resolved": "0.10.0", - "contentHash": "4/IDFCJfIeg6bix9apmUtIMwvOsiwqdEexeO/R2D4GReIGPLIRODTpId/l4LRSrAJk9lEO3Zx1H0Zx6uohJDNg==" + "resolved": "1.0.0", + "contentHash": "BeO8hEgs/c8Ls2647fPfieMngncvf0D0xYNDfIO59MolxtCtVjFRd6SRc+7tj8VMqkVOuJcnc9eh4ngI2cAmLQ==" }, "xunit.assert": { "type": "Transitive", - "resolved": "2.4.1", - "contentHash": "O/Oe0BS5RmSsM+LQOb041TzuPo5MdH2Rov+qXGS37X+KFG1Hxz7kopYklM5+1Y+tRGeXrOx5+Xne1RuqLFQoyQ==", + "resolved": "2.4.2", + "contentHash": "pxJISOFjn2XTTi1mcDCkRZrTFb9OtRRCtx2kZFNF51GdReLr1ls2rnyxvAS4JO247K3aNtflvh5Q0346K5BROA==", "dependencies": { "NETStandard.Library": "1.6.1" } }, "xunit.core": { "type": "Transitive", - "resolved": "2.4.1", - "contentHash": "Zsj5OMU6JasNGERXZy8s72+pcheG6Q15atS5XpZXqAtULuyQiQ6XNnUsp1gyfC6WgqScqMvySiEHmHcOG6Eg0Q==", + "resolved": "2.4.2", + "contentHash": "KB4yGCxNqIVyekhJLXtKSEq6BaXVp/JO3mbGVE1hxypZTLEe7h+sTbAhpA+yZW2dPtXTuiW+C1B2oxxHEkrmOw==", "dependencies": { - "xunit.extensibility.core": "[2.4.1]", - "xunit.extensibility.execution": "[2.4.1]" + "xunit.extensibility.core": "[2.4.2]", + "xunit.extensibility.execution": "[2.4.2]" } }, "xunit.extensibility.core": { "type": "Transitive", - "resolved": "2.4.1", - "contentHash": "yKZKm/8QNZnBnGZFD9SewkllHBiK0DThybQD/G4PiAmQjKtEZyHi6ET70QPU9KtSMJGRYS6Syk7EyR2EVDU4Kg==", + "resolved": "2.4.2", + "contentHash": "W1BoXTIN1C6kpVSMw25huSet25ky6IAQUNovu3zGOGN/jWnbgSoTyCrlIhmXSg0tH5nEf8q7h3OjNHOjyu5PfA==", "dependencies": { "NETStandard.Library": "1.6.1", "xunit.abstractions": "2.0.3" @@ -1766,49 +1759,65 @@ }, "xunit.extensibility.execution": { "type": "Transitive", - "resolved": "2.4.1", - "contentHash": "7e/1jqBpcb7frLkB6XDrHCGXAbKN4Rtdb88epYxCSRQuZDRW8UtTfdTEVpdTl8s4T56e07hOBVd4G0OdCxIY2A==", + "resolved": "2.4.2", + "contentHash": "CZmgcKkwpyo8FlupZdWpJCryrAOWLh1FBPG6gmVZuPQkGQsim/oL4PcP4nfrC2hHgXUFtluvaJ0Sp9PQKUMNpg==", "dependencies": { "NETStandard.Library": "1.6.1", - "xunit.extensibility.core": "[2.4.1]" + "xunit.extensibility.core": "[2.4.2]" } }, "entitydb.abstractions": { - "type": "Project" + "type": "Project", + "dependencies": { + "System.Linq.Async": "6.0.1" + } }, "entitydb.common": { "type": "Project", "dependencies": { - "EntityDb.Abstractions": "1.0.0" + "EntityDb.Abstractions": "1.0.0", + "System.Linq.Async": "6.0.1" } }, "entitydb.common.tests": { "type": "Project", "dependencies": { - "Bogus": "34.0.1", + "Bogus": "34.0.2", "EntityDb.Common": "1.0.0", "EntityDb.InMemory": "1.0.0", "EntityDb.MongoDb.Provisioner": "1.0.0", + "EntityDb.Npgsql.Provisioner": "1.0.0", "EntityDb.Redis": "1.0.0", - "Microsoft.NET.Test.Sdk": "17.0.0", - "Moq": "4.18.1", + "Microsoft.NET.Test.Sdk": "17.2.0", + "Moq": "4.18.2", "Shouldly": "4.0.3", - "Xunit.DependencyInjection": "8.3.0", - "Xunit.DependencyInjection.Logging": "8.0.0", - "xunit": "2.4.1" + "System.Linq.Async": "6.0.1", + "Testcontainers": "2.1.0", + "Xunit.DependencyInjection": "8.5.0", + "Xunit.DependencyInjection.Logging": "8.0.1", + "xunit": "2.4.2" } }, "entitydb.inmemory": { "type": "Project", "dependencies": { - "EntityDb.Common": "1.0.0" + "EntityDb.Common": "1.0.0", + "System.Linq.Async": "6.0.1" + } + }, + "entitydb.json": { + "type": "Project", + "dependencies": { + "EntityDb.Common": "1.0.0", + "System.Linq.Async": "6.0.1" } }, "entitydb.mongodb": { "type": "Project", "dependencies": { "EntityDb.Common": "1.0.0", - "MongoDB.Driver": "2.16.1" + "MongoDB.Driver": "2.17.1", + "System.Linq.Async": "6.0.1" } }, "entitydb.mongodb.provisioner": { @@ -1816,14 +1825,42 @@ "dependencies": { "EntityDb.MongoDb": "1.0.0", "System.CommandLine": "2.0.0-beta4.22272.1", - "System.CommandLine.NamingConventionBinder": "2.0.0-beta4.22272.1" + "System.CommandLine.NamingConventionBinder": "2.0.0-beta4.22272.1", + "System.Linq.Async": "6.0.1" + } + }, + "entitydb.npgsql": { + "type": "Project", + "dependencies": { + "EntityDb.SqlDb": "1.0.0", + "Npgsql": "6.0.6", + "System.Linq.Async": "6.0.1" + } + }, + "entitydb.npgsql.provisioner": { + "type": "Project", + "dependencies": { + "EntityDb.Npgsql": "1.0.0", + "System.CommandLine": "2.0.0-beta4.22272.1", + "System.CommandLine.NamingConventionBinder": "2.0.0-beta4.22272.1", + "System.Linq.Async": "6.0.1" } }, "entitydb.redis": { "type": "Project", "dependencies": { "EntityDb.Common": "1.0.0", - "StackExchange.Redis": "2.6.48" + "EntityDb.Json": "1.0.0", + "StackExchange.Redis": "2.6.48", + "System.Linq.Async": "6.0.1" + } + }, + "entitydb.sqldb": { + "type": "Project", + "dependencies": { + "EntityDb.Common": "1.0.0", + "EntityDb.Json": "1.0.0", + "System.Linq.Async": "6.0.1" } } } diff --git a/test/EntityDb.Mvc.Tests/Agents/HttpContextAgentAccessorTests.cs b/test/EntityDb.Mvc.Tests/Agents/HttpContextAgentAccessorTests.cs index 8667734e..8a27a3a6 100644 --- a/test/EntityDb.Mvc.Tests/Agents/HttpContextAgentAccessorTests.cs +++ b/test/EntityDb.Mvc.Tests/Agents/HttpContextAgentAccessorTests.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using EntityDb.Common.Tests.Agents; +using EntityDb.Common.Tests.Agents; using EntityDb.Mvc.Agents; using EntityDb.Mvc.Tests.Seeder; using Microsoft.AspNetCore.Http; diff --git a/test/EntityDb.Mvc.Tests/Agents/HttpContextAgentSignatureTests.cs b/test/EntityDb.Mvc.Tests/Agents/HttpContextAgentSignatureTests.cs index 37c47d51..7c12431e 100644 --- a/test/EntityDb.Mvc.Tests/Agents/HttpContextAgentSignatureTests.cs +++ b/test/EntityDb.Mvc.Tests/Agents/HttpContextAgentSignatureTests.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using EntityDb.Mvc.Agents; +using EntityDb.Mvc.Agents; using EntityDb.Mvc.Tests.Seeder; using Shouldly; using Xunit; diff --git a/test/EntityDb.Mvc.Tests/Seeder/HttpContextSeeder.cs b/test/EntityDb.Mvc.Tests/Seeder/HttpContextSeeder.cs index 91202522..6eadad4c 100644 --- a/test/EntityDb.Mvc.Tests/Seeder/HttpContextSeeder.cs +++ b/test/EntityDb.Mvc.Tests/Seeder/HttpContextSeeder.cs @@ -1,5 +1,4 @@ -using System.Linq; -using Bogus; +using Bogus; using EntityDb.Abstractions.ValueObjects; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; diff --git a/test/EntityDb.Mvc.Tests/Seeder/HttpContextSeederOptions.cs b/test/EntityDb.Mvc.Tests/Seeder/HttpContextSeederOptions.cs index 12b7fb68..cd995628 100644 --- a/test/EntityDb.Mvc.Tests/Seeder/HttpContextSeederOptions.cs +++ b/test/EntityDb.Mvc.Tests/Seeder/HttpContextSeederOptions.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; - -namespace EntityDb.Mvc.Tests.Seeder; +namespace EntityDb.Mvc.Tests.Seeder; public class HttpContextSeederOptions { diff --git a/test/EntityDb.Mvc.Tests/packages.lock.json b/test/EntityDb.Mvc.Tests/packages.lock.json index 28eb3497..b9235399 100644 --- a/test/EntityDb.Mvc.Tests/packages.lock.json +++ b/test/EntityDb.Mvc.Tests/packages.lock.json @@ -4,9 +4,9 @@ "net6.0": { "Bogus": { "type": "Direct", - "requested": "[34.0.1, )", - "resolved": "34.0.1", - "contentHash": "49iq7QrD0wb7V4/FcK8p3dWdJxNUbojaqK9L6KRvdikIuRjt38EsNp7QXICcYdbYw01K8BHUdxlnTNn/YX3qDA==" + "requested": "[34.0.2, )", + "resolved": "34.0.2", + "contentHash": "2KQAuMn3fLAQ2r6jeiffZnpv0bi3GCW3iRB2v1KeHIEBu8MNTh9dBlLTZwGvM0pr+9doKkU8L5JgCURmTmT88A==" }, "coverlet.collector": { "type": "Direct", @@ -16,22 +16,21 @@ }, "Microsoft.NET.Test.Sdk": { "type": "Direct", - "requested": "[17.0.0, )", - "resolved": "17.0.0", - "contentHash": "fJcnMY3jX1MzJvhGvUWauRhU5eQsOaHdwlrcnI3NabBhbi8WLAkMFI8d0YnewA/+b9q/U7vbhp8Xmh1vJ05FYQ==", + "requested": "[17.2.0, )", + "resolved": "17.2.0", + "contentHash": "kYmkDYbcDd+jNvmMH4TMtgHjsUYbIsWENM2VcjB0X7TawXbehL5I8OIsu2TgFS/nQCgZE94InrqMxrm7WDy+Lw==", "dependencies": { - "Microsoft.CodeCoverage": "17.0.0", - "Microsoft.TestPlatform.TestHost": "17.0.0" + "Microsoft.CodeCoverage": "17.2.0", + "Microsoft.TestPlatform.TestHost": "17.2.0" } }, "Moq": { "type": "Direct", - "requested": "[4.18.1, )", - "resolved": "4.18.1", - "contentHash": "MmZIKNyvn8VrivSaqA8tqy5DmwUievC9zsuNTrcb00oY4IeGq6fXT5BQK329lZ05/tyi5vp30AWe9fl0d2PZQg==", + "requested": "[4.18.2, )", + "resolved": "4.18.2", + "contentHash": "SjxKYS5nX6prcaT8ZjbkONh3vnh0Rxru09+gQ1a07v4TM530Oe/jq3Q4dOZPfo1wq0LYmTgLOZKrqRfEx4auPw==", "dependencies": { - "Castle.Core": "5.0.0", - "System.Threading.Tasks.Extensions": "4.5.4" + "Castle.Core": "5.1.0" } }, "Shouldly": { @@ -46,22 +45,31 @@ "System.Memory": "4.5.4" } }, + "System.Linq.Async": { + "type": "Direct", + "requested": "[6.0.1, )", + "resolved": "6.0.1", + "contentHash": "0YhHcaroWpQ9UCot3Pizah7ryAzQhNvobLMSxeDIGmnXfkQn8u5owvpOH0K6EVB+z9L7u6Cc4W17Br/+jyttEQ==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "6.0.0" + } + }, "xunit": { "type": "Direct", - "requested": "[2.4.1, )", - "resolved": "2.4.1", - "contentHash": "XNR3Yz9QTtec16O0aKcO6+baVNpXmOnPUxDkCY97J+8krUYxPvXT1szYYEUdKk4sB8GOI2YbAjRIOm8ZnXRfzQ==", + "requested": "[2.4.2, )", + "resolved": "2.4.2", + "contentHash": "6Mj73Ont3zj2CJuoykVJfE0ZmRwn7C+pTuRP8c4bnaaTFjwNG6tGe0prJ1yIbMe9AHrpDys63ctWacSsFJWK/w==", "dependencies": { - "xunit.analyzers": "0.10.0", - "xunit.assert": "[2.4.1]", - "xunit.core": "[2.4.1]" + "xunit.analyzers": "1.0.0", + "xunit.assert": "2.4.2", + "xunit.core": "[2.4.2]" } }, "Xunit.DependencyInjection": { "type": "Direct", - "requested": "[8.3.0, )", - "resolved": "8.3.0", - "contentHash": "uh4rHDT7IBpDB18zZWvP+jf7nbUYsGb71mHkeatNu9EvfTlY5MvtKGANBPwMEuxvnRhgypMSa14RhwunSvH5Ww==", + "requested": "[8.5.0, )", + "resolved": "8.5.0", + "contentHash": "OnSFB9x3MaXYFq9VFjdqoHgjOOjBOUxYFNkiQ3OXVe7I6r/KGs4yHJ3FAqZwddjNgKeRX1PEwiDWnDJOuonECQ==", "dependencies": { "Microsoft.Bcl.AsyncInterfaces": "1.0.0", "Microsoft.Extensions.Hosting": "2.1.0", @@ -71,23 +79,23 @@ }, "Xunit.DependencyInjection.Logging": { "type": "Direct", - "requested": "[8.0.0, )", - "resolved": "8.0.0", - "contentHash": "EfFGSxOGdu5k63+LBiPmG4rZ6kgTJF0WRES2MUriJ0LeLPD+0WJDNVjitx338O89ctt70gJ+JT9ogX4/74Esbg==", + "requested": "[8.0.1, )", + "resolved": "8.0.1", + "contentHash": "SXsc9Cp9LrpH3F9+35CbtCv0zuBw8491t3o5rK1/TVYeuwzVVR2h60/uGRYIs2GyVcKNRG7hOH8MbjPaap1sHQ==", "dependencies": { - "Xunit.DependencyInjection": "8.0.0" + "Xunit.DependencyInjection": "8.4.1" } }, "xunit.runner.visualstudio": { "type": "Direct", - "requested": "[2.4.3, )", - "resolved": "2.4.3", - "contentHash": "kZZSmOmKA8OBlAJaquPXnJJLM9RwQ27H7BMVqfMLUcTi9xHinWGJiWksa3D4NEtz0wZ/nxd2mogObvBgJKCRhQ==" + "requested": "[2.4.5, )", + "resolved": "2.4.5", + "contentHash": "OwHamvBdUKgqsXfBzWiCW/O98BTx81UKzx2bieIOQI7CZFE5NEQZGi8PBQGIKawDW96xeRffiNf20SjfC0x9hw==" }, "Castle.Core": { "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "edc8jjyXqzzy8jFdhs36FZdwmlDDTgqPb2Zy1Q5F/f2uAc88bu/VS/0Tpvgupmpl9zJOvOo5ZizVANb0ltN1NQ==", + "resolved": "5.1.0", + "contentHash": "31UJpTHOiWq95CDOHazE3Ub/hE/PydNWsJMwnEVTqFFP4WhAugwpaVGxzOxKgNeSUUeqS2W6lxV+q7u1pAOfXg==", "dependencies": { "System.Diagnostics.EventLog": "6.0.0" } @@ -109,6 +117,16 @@ "Microsoft.Win32.Registry": "5.0.0" } }, + "Docker.DotNet": { + "type": "Transitive", + "resolved": "3.125.10", + "contentHash": "sKu8AFiRPao1IqYPUT2mAxT0c7F+dgEfOonuVfgn5FYdHccHdL9Ge4Jsem0KHlxYzqE6QpOFDt1hR/J1XzqogQ==", + "dependencies": { + "Newtonsoft.Json": "13.0.1", + "System.Buffers": "4.5.1", + "System.Threading.Tasks.Extensions": "4.5.4" + } + }, "EmptyFiles": { "type": "Transitive", "resolved": "2.3.3", @@ -116,13 +134,13 @@ }, "Microsoft.Bcl.AsyncInterfaces": { "type": "Transitive", - "resolved": "1.0.0", - "contentHash": "K63Y4hORbBcKLWH5wnKgzyn7TOfYzevIEwIedQHBIkmkEBA9SCqgvom+XTuE+fAFGvINGkhFItaZ2dvMGdT5iw==" + "resolved": "6.0.0", + "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==" }, "Microsoft.CodeCoverage": { "type": "Transitive", - "resolved": "17.0.0", - "contentHash": "+B+09FPYBtf+cXfZOPIgpnP5mzLq5QdlBo+JEFy9CdqBaWHWE/YMY0Mos9uDsZhcgFegJm9GigAgMyqBZyfq+Q==" + "resolved": "17.2.0", + "contentHash": "MsKhJmwIfHxNDbTIlgQy29UpWSWPpbZOQPhQ7xalRy+ABnl8/neFHZGzSP3XlpW2dKAXHTFrtIcKzW/kopY2Bg==" }, "Microsoft.CSharp": { "type": "Transitive", @@ -224,8 +242,8 @@ }, "Microsoft.Extensions.Logging.Abstractions": { "type": "Transitive", - "resolved": "2.1.0", - "contentHash": "GfD2VtvN9z1W+m6pZZe98yh9VWTSdNY2dZSxtca9uFIY6aBI6twvskMvLO/ktClBOTQmAov/7Em+IWFlHepa0A==" + "resolved": "3.1.26", + "contentHash": "sCDtgEvfq0UhK6k9N7qCqvIsEud0T0eVu4UEW5G7urctFxRA8UUlcyrfFHH/k0tkEplZAv4EN8Xbj8j7BQNPhA==" }, "Microsoft.Extensions.Options": { "type": "Transitive", @@ -257,19 +275,19 @@ }, "Microsoft.TestPlatform.ObjectModel": { "type": "Transitive", - "resolved": "17.0.0", - "contentHash": "WMugCdPkA8U/BsSRc+3RN+DXcaYSDvp/s0MofVld08iF1O5fek4iKecygk6NruNf1rgJsv4LK71mrwbyeqhzHA==", + "resolved": "17.2.0", + "contentHash": "7j1KYDHLhU98XnCEbECMncXLydI9fNiFLcFsiBsP3lV6EkHOaj5kTPAWHYkKnPGRC9TbZUboSQq8rWI4dTQsxg==", "dependencies": { - "NuGet.Frameworks": "5.0.0", + "NuGet.Frameworks": "5.11.0", "System.Reflection.Metadata": "1.6.0" } }, "Microsoft.TestPlatform.TestHost": { "type": "Transitive", - "resolved": "17.0.0", - "contentHash": "xkKFzm0hylHF0SlDj78ACYMJC/i8fQ3i16sDDNYoKnjTsstGSQfuSBJ+QT4nqRXk/fOiYTh+iY0KIX5N7HTLuQ==", + "resolved": "17.2.0", + "contentHash": "bI67J+hers241h7eD2eecS02p9CbKcQDIeoRvO4FgMlTWg2ZTzc0D3uWLYr5U+K5x9O1pNmyMoMDbYIeWY/TWw==", "dependencies": { - "Microsoft.TestPlatform.ObjectModel": "17.0.0", + "Microsoft.TestPlatform.ObjectModel": "17.2.0", "Newtonsoft.Json": "9.0.1" } }, @@ -361,38 +379,38 @@ }, "MongoDB.Bson": { "type": "Transitive", - "resolved": "2.16.1", - "contentHash": "d647KTPQ7hWqJmvCg80iiVdm239llaUwMyIeRF/0zKpN+ddRWh9jT/g6R6WQrmi4qd7yodvv/Jn0rpEqh4QN8g==", + "resolved": "2.17.1", + "contentHash": "IBr5w6ygeUCTobiS4J2UlYeIsnjSJvOOf31g60EkRa3NIeyrYs7Y51HeOvJ8r6NPcKv1hLj8xwoop6hDTetAdA==", "dependencies": { "System.Runtime.CompilerServices.Unsafe": "5.0.0" } }, "MongoDB.Driver": { "type": "Transitive", - "resolved": "2.16.1", - "contentHash": "LqDWfRG7gM1tZKcG9Q/vuQGYF5GsBuxUF5KcOgvWrE6P7pSkOSL9xGZ7ABZ6XRVECGEQs+N6GyU1E4ViI4lh+g==", + "resolved": "2.17.1", + "contentHash": "A5Yvm3RUdkSYnvKWVb/bZfvhzG+L+t0n80JuUXf0p2QG1TbtqHE9hX/FBK+BoF7sw9rzUTw8VHYeqX5rT0rxdA==", "dependencies": { - "MongoDB.Bson": "2.16.1", - "MongoDB.Driver.Core": "2.16.1", - "MongoDB.Libmongocrypt": "1.5.3" + "MongoDB.Bson": "2.17.1", + "MongoDB.Driver.Core": "2.17.1", + "MongoDB.Libmongocrypt": "1.5.5" } }, "MongoDB.Driver.Core": { "type": "Transitive", - "resolved": "2.16.1", - "contentHash": "oJZnXHnAyTd/haHYdbfKMRmPEZ1fFrndv8xhorHeTkUDeGgsPA89vpGMHcjppUyHMYBpLgHbn6GoMkleHKsTHg==", + "resolved": "2.17.1", + "contentHash": "lfuuQvCXcco6mG096PL8xRO+dBdHsDTR3DiYfK/ICHgFlL5RfKlBuE0xClEGKtaZ4Spe28/fF/GUcrrA/yfoAQ==", "dependencies": { "DnsClient": "1.6.1", - "MongoDB.Bson": "2.16.1", - "MongoDB.Libmongocrypt": "1.5.3", + "MongoDB.Bson": "2.17.1", + "MongoDB.Libmongocrypt": "1.5.5", "SharpCompress": "0.30.1", "System.Buffers": "4.5.1" } }, "MongoDB.Libmongocrypt": { "type": "Transitive", - "resolved": "1.5.3", - "contentHash": "OWWxuyuxbjAmOLPoaoUEYnIW4F7qexS6XYOdu6absxyGAqLBWEY+M4WY2Y0km2UUG1+QOPdebpb/7cg5BIEbdw==" + "resolved": "1.5.5", + "contentHash": "0DV4l2PjXirSJHD/b+LpOK3IfUDvkbpvvZBM2w1aYL6E/4vbhfyr/FP5laDNx2zRylqN1hIZO+EL7NgO/5GpVg==" }, "NETStandard.Library": { "type": "Transitive", @@ -447,37 +465,21 @@ }, "Newtonsoft.Json": { "type": "Transitive", - "resolved": "9.0.1", - "contentHash": "U82mHQSKaIk+lpSVCbWYKNavmNH1i5xrExDEquU1i6I5pV6UMOqRnJRSlKO3cMPfcpp0RgDY+8jUXHdQ4IfXvw==", - "dependencies": { - "Microsoft.CSharp": "4.0.1", - "System.Collections": "4.0.11", - "System.Diagnostics.Debug": "4.0.11", - "System.Dynamic.Runtime": "4.0.11", - "System.Globalization": "4.0.11", - "System.IO": "4.1.0", - "System.Linq": "4.1.0", - "System.Linq.Expressions": "4.1.0", - "System.ObjectModel": "4.0.12", - "System.Reflection": "4.1.0", - "System.Reflection.Extensions": "4.0.1", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0", - "System.Runtime.Extensions": "4.1.0", - "System.Runtime.Serialization.Primitives": "4.1.1", - "System.Text.Encoding": "4.0.11", - "System.Text.Encoding.Extensions": "4.0.11", - "System.Text.RegularExpressions": "4.1.0", - "System.Threading": "4.0.11", - "System.Threading.Tasks": "4.0.11", - "System.Xml.ReaderWriter": "4.0.11", - "System.Xml.XDocument": "4.0.11" + "resolved": "13.0.1", + "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==" + }, + "Npgsql": { + "type": "Transitive", + "resolved": "6.0.6", + "contentHash": "IIwnoJp0sFkhAydT/KKe/0NhlJKhYPIrXSE95AuU/2dqHNI9alxvjClJSGL+QE8NGqq1SFn+NenxVtm/JYsrJg==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0" } }, "NuGet.Frameworks": { "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "c5JVjuVAm4f7E9Vj+v09Z9s2ZsqFDjBpcsyS3M9xRo0bEdm/LVZSzLxxNvfvAwRiiE8nwe1h2G4OwiwlzFKXlA==" + "resolved": "5.11.0", + "contentHash": "eaiXkUjC4NPcquGWzAGMXjuxvLwc6XGKMptSyOGQeT0X70BUZObuybJFZLA0OfTdueLd3US23NBPTBb6iF3V1Q==" }, "Pipelines.Sockets.Unofficial": { "type": "Transitive", @@ -655,6 +657,11 @@ "resolved": "0.30.1", "contentHash": "XqD4TpfyYGa7QTPzaGlMVbcecKnXy4YmYLDWrU+JIj7IuRNl7DH2END+Ll7ekWIY8o3dAMWLFDE1xdhfIWD1nw==" }, + "SharpZipLib": { + "type": "Transitive", + "resolved": "1.3.3", + "contentHash": "N8+hwhsKZm25tDJfWpBSW7EGhH/R7EMuiX+KJ4C4u+fCWVc1lJ5zg1u3S1RPPVYgTqhx/C3hxrqUpi6RwK5+Tg==" + }, "StackExchange.Redis": { "type": "Transitive", "resolved": "2.6.48", @@ -888,28 +895,6 @@ "Microsoft.Win32.SystemEvents": "5.0.0" } }, - "System.Dynamic.Runtime": { - "type": "Transitive", - "resolved": "4.0.11", - "contentHash": "db34f6LHYM0U0JpE+sOmjar27BnqTVkbLJhgfwMpTdgTigG/Hna3m2MYVwnFzGGKnEJk2UXFuoVTr8WUbU91/A==", - "dependencies": { - "System.Collections": "4.0.11", - "System.Diagnostics.Debug": "4.0.11", - "System.Globalization": "4.0.11", - "System.Linq": "4.1.0", - "System.Linq.Expressions": "4.1.0", - "System.ObjectModel": "4.0.12", - "System.Reflection": "4.1.0", - "System.Reflection.Emit": "4.0.1", - "System.Reflection.Emit.ILGeneration": "4.0.1", - "System.Reflection.Primitives": "4.0.1", - "System.Reflection.TypeExtensions": "4.1.0", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0", - "System.Runtime.Extensions": "4.1.0", - "System.Threading": "4.0.11" - } - }, "System.Formats.Asn1": { "type": "Transitive", "resolved": "5.0.0", @@ -1353,15 +1338,6 @@ "System.Runtime.Extensions": "4.3.0" } }, - "System.Runtime.Serialization.Primitives": { - "type": "Transitive", - "resolved": "4.1.1", - "contentHash": "HZ6Du5QrTG8MNJbf4e4qMO3JRAkIboGT5Fk804uZtg3Gq516S7hAqTm2UZKUHa7/6HUGdVy3AqMQKbns06G/cg==", - "dependencies": { - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0" - } - }, "System.Security.AccessControl": { "type": "Transitive", "resolved": "5.0.0", @@ -1628,6 +1604,11 @@ "System.Text.Encoding": "4.3.0" } }, + "System.Text.Json": { + "type": "Transitive", + "resolved": "4.7.2", + "contentHash": "TcMd95wcrubm9nHvJEQs70rC0H/8omiSGGpU4FQ/ZA1URIqD4pjmFJh2Mfv1yH1eHgJDWTi2hMDXwTET+zOOyg==" + }, "System.Text.RegularExpressions": { "type": "Transitive", "resolved": "4.3.0", @@ -1728,6 +1709,18 @@ "System.Xml.ReaderWriter": "4.3.0" } }, + "Testcontainers": { + "type": "Transitive", + "resolved": "2.1.0", + "contentHash": "ESpfTlnntNJfPoQ2gg/lNt2S+SuFAI7XYISfNWWKrroVOuJKGq/HsXQVA9Yj/n+fQ8TgpbMyGGiwZGxkbbVAKA==", + "dependencies": { + "Docker.DotNet": "3.125.10", + "Microsoft.Bcl.AsyncInterfaces": "1.1.1", + "Microsoft.Extensions.Logging.Abstractions": "3.1.26", + "SharpZipLib": "1.3.3", + "System.Text.Json": "4.7.2" + } + }, "xunit.abstractions": { "type": "Transitive", "resolved": "2.0.3", @@ -1735,30 +1728,30 @@ }, "xunit.analyzers": { "type": "Transitive", - "resolved": "0.10.0", - "contentHash": "4/IDFCJfIeg6bix9apmUtIMwvOsiwqdEexeO/R2D4GReIGPLIRODTpId/l4LRSrAJk9lEO3Zx1H0Zx6uohJDNg==" + "resolved": "1.0.0", + "contentHash": "BeO8hEgs/c8Ls2647fPfieMngncvf0D0xYNDfIO59MolxtCtVjFRd6SRc+7tj8VMqkVOuJcnc9eh4ngI2cAmLQ==" }, "xunit.assert": { "type": "Transitive", - "resolved": "2.4.1", - "contentHash": "O/Oe0BS5RmSsM+LQOb041TzuPo5MdH2Rov+qXGS37X+KFG1Hxz7kopYklM5+1Y+tRGeXrOx5+Xne1RuqLFQoyQ==", + "resolved": "2.4.2", + "contentHash": "pxJISOFjn2XTTi1mcDCkRZrTFb9OtRRCtx2kZFNF51GdReLr1ls2rnyxvAS4JO247K3aNtflvh5Q0346K5BROA==", "dependencies": { "NETStandard.Library": "1.6.1" } }, "xunit.core": { "type": "Transitive", - "resolved": "2.4.1", - "contentHash": "Zsj5OMU6JasNGERXZy8s72+pcheG6Q15atS5XpZXqAtULuyQiQ6XNnUsp1gyfC6WgqScqMvySiEHmHcOG6Eg0Q==", + "resolved": "2.4.2", + "contentHash": "KB4yGCxNqIVyekhJLXtKSEq6BaXVp/JO3mbGVE1hxypZTLEe7h+sTbAhpA+yZW2dPtXTuiW+C1B2oxxHEkrmOw==", "dependencies": { - "xunit.extensibility.core": "[2.4.1]", - "xunit.extensibility.execution": "[2.4.1]" + "xunit.extensibility.core": "[2.4.2]", + "xunit.extensibility.execution": "[2.4.2]" } }, "xunit.extensibility.core": { "type": "Transitive", - "resolved": "2.4.1", - "contentHash": "yKZKm/8QNZnBnGZFD9SewkllHBiK0DThybQD/G4PiAmQjKtEZyHi6ET70QPU9KtSMJGRYS6Syk7EyR2EVDU4Kg==", + "resolved": "2.4.2", + "contentHash": "W1BoXTIN1C6kpVSMw25huSet25ky6IAQUNovu3zGOGN/jWnbgSoTyCrlIhmXSg0tH5nEf8q7h3OjNHOjyu5PfA==", "dependencies": { "NETStandard.Library": "1.6.1", "xunit.abstractions": "2.0.3" @@ -1766,49 +1759,65 @@ }, "xunit.extensibility.execution": { "type": "Transitive", - "resolved": "2.4.1", - "contentHash": "7e/1jqBpcb7frLkB6XDrHCGXAbKN4Rtdb88epYxCSRQuZDRW8UtTfdTEVpdTl8s4T56e07hOBVd4G0OdCxIY2A==", + "resolved": "2.4.2", + "contentHash": "CZmgcKkwpyo8FlupZdWpJCryrAOWLh1FBPG6gmVZuPQkGQsim/oL4PcP4nfrC2hHgXUFtluvaJ0Sp9PQKUMNpg==", "dependencies": { "NETStandard.Library": "1.6.1", - "xunit.extensibility.core": "[2.4.1]" + "xunit.extensibility.core": "[2.4.2]" } }, "entitydb.abstractions": { - "type": "Project" + "type": "Project", + "dependencies": { + "System.Linq.Async": "6.0.1" + } }, "entitydb.common": { "type": "Project", "dependencies": { - "EntityDb.Abstractions": "1.0.0" + "EntityDb.Abstractions": "1.0.0", + "System.Linq.Async": "6.0.1" } }, "entitydb.common.tests": { "type": "Project", "dependencies": { - "Bogus": "34.0.1", + "Bogus": "34.0.2", "EntityDb.Common": "1.0.0", "EntityDb.InMemory": "1.0.0", "EntityDb.MongoDb.Provisioner": "1.0.0", + "EntityDb.Npgsql.Provisioner": "1.0.0", "EntityDb.Redis": "1.0.0", - "Microsoft.NET.Test.Sdk": "17.0.0", - "Moq": "4.18.1", + "Microsoft.NET.Test.Sdk": "17.2.0", + "Moq": "4.18.2", "Shouldly": "4.0.3", - "Xunit.DependencyInjection": "8.3.0", - "Xunit.DependencyInjection.Logging": "8.0.0", - "xunit": "2.4.1" + "System.Linq.Async": "6.0.1", + "Testcontainers": "2.1.0", + "Xunit.DependencyInjection": "8.5.0", + "Xunit.DependencyInjection.Logging": "8.0.1", + "xunit": "2.4.2" } }, "entitydb.inmemory": { "type": "Project", "dependencies": { - "EntityDb.Common": "1.0.0" + "EntityDb.Common": "1.0.0", + "System.Linq.Async": "6.0.1" + } + }, + "entitydb.json": { + "type": "Project", + "dependencies": { + "EntityDb.Common": "1.0.0", + "System.Linq.Async": "6.0.1" } }, "entitydb.mongodb": { "type": "Project", "dependencies": { "EntityDb.Common": "1.0.0", - "MongoDB.Driver": "2.16.1" + "MongoDB.Driver": "2.17.1", + "System.Linq.Async": "6.0.1" } }, "entitydb.mongodb.provisioner": { @@ -1816,20 +1825,49 @@ "dependencies": { "EntityDb.MongoDb": "1.0.0", "System.CommandLine": "2.0.0-beta4.22272.1", - "System.CommandLine.NamingConventionBinder": "2.0.0-beta4.22272.1" + "System.CommandLine.NamingConventionBinder": "2.0.0-beta4.22272.1", + "System.Linq.Async": "6.0.1" } }, "entitydb.mvc": { "type": "Project", "dependencies": { - "EntityDb.Common": "1.0.0" + "EntityDb.Common": "1.0.0", + "System.Linq.Async": "6.0.1" + } + }, + "entitydb.npgsql": { + "type": "Project", + "dependencies": { + "EntityDb.SqlDb": "1.0.0", + "Npgsql": "6.0.6", + "System.Linq.Async": "6.0.1" + } + }, + "entitydb.npgsql.provisioner": { + "type": "Project", + "dependencies": { + "EntityDb.Npgsql": "1.0.0", + "System.CommandLine": "2.0.0-beta4.22272.1", + "System.CommandLine.NamingConventionBinder": "2.0.0-beta4.22272.1", + "System.Linq.Async": "6.0.1" } }, "entitydb.redis": { "type": "Project", "dependencies": { "EntityDb.Common": "1.0.0", - "StackExchange.Redis": "2.6.48" + "EntityDb.Json": "1.0.0", + "StackExchange.Redis": "2.6.48", + "System.Linq.Async": "6.0.1" + } + }, + "entitydb.sqldb": { + "type": "Project", + "dependencies": { + "EntityDb.Common": "1.0.0", + "EntityDb.Json": "1.0.0", + "System.Linq.Async": "6.0.1" } } } diff --git a/test/EntityDb.Redis.Tests/Envelopes/JsonElementEnvelopeTests.cs b/test/EntityDb.Redis.Tests/Envelopes/JsonElementEnvelopeTests.cs index 59dca5fc..f56b3976 100644 --- a/test/EntityDb.Redis.Tests/Envelopes/JsonElementEnvelopeTests.cs +++ b/test/EntityDb.Redis.Tests/Envelopes/JsonElementEnvelopeTests.cs @@ -1,17 +1,15 @@ -using System; -using System.Text; -using System.Text.Json; +using System.Text; using EntityDb.Common.Tests.Envelopes; namespace EntityDb.Redis.Tests.Envelopes; -public class JsonElementEnvelopeTests : EnvelopeTestsBase +public class JsonElementEnvelopeTests : EnvelopeTestsBase { public JsonElementEnvelopeTests(IServiceProvider startupServiceProvider) : base(startupServiceProvider) { } - protected override byte[] GenerateCorruptedBytes() + protected override byte[] GenerateCorruptedSerializedData() { const string invalidJson = "I AM A STRING VALUE, NOT JSON!"; diff --git a/test/EntityDb.Redis.Tests/Sessions/RedisSessionTests.cs b/test/EntityDb.Redis.Tests/Sessions/RedisSessionTests.cs index 36d80e99..eb341fc1 100644 --- a/test/EntityDb.Redis.Tests/Sessions/RedisSessionTests.cs +++ b/test/EntityDb.Redis.Tests/Sessions/RedisSessionTests.cs @@ -1,6 +1,4 @@ -using System; -using System.Threading.Tasks; -using EntityDb.Common.Exceptions; +using EntityDb.Common.Exceptions; using EntityDb.Common.Tests; using EntityDb.Redis.Sessions; using Shouldly; diff --git a/test/EntityDb.Redis.Tests/packages.lock.json b/test/EntityDb.Redis.Tests/packages.lock.json index 4ae4e6a4..61c5e105 100644 --- a/test/EntityDb.Redis.Tests/packages.lock.json +++ b/test/EntityDb.Redis.Tests/packages.lock.json @@ -4,9 +4,9 @@ "net6.0": { "Bogus": { "type": "Direct", - "requested": "[34.0.1, )", - "resolved": "34.0.1", - "contentHash": "49iq7QrD0wb7V4/FcK8p3dWdJxNUbojaqK9L6KRvdikIuRjt38EsNp7QXICcYdbYw01K8BHUdxlnTNn/YX3qDA==" + "requested": "[34.0.2, )", + "resolved": "34.0.2", + "contentHash": "2KQAuMn3fLAQ2r6jeiffZnpv0bi3GCW3iRB2v1KeHIEBu8MNTh9dBlLTZwGvM0pr+9doKkU8L5JgCURmTmT88A==" }, "coverlet.collector": { "type": "Direct", @@ -16,22 +16,21 @@ }, "Microsoft.NET.Test.Sdk": { "type": "Direct", - "requested": "[17.0.0, )", - "resolved": "17.0.0", - "contentHash": "fJcnMY3jX1MzJvhGvUWauRhU5eQsOaHdwlrcnI3NabBhbi8WLAkMFI8d0YnewA/+b9q/U7vbhp8Xmh1vJ05FYQ==", + "requested": "[17.2.0, )", + "resolved": "17.2.0", + "contentHash": "kYmkDYbcDd+jNvmMH4TMtgHjsUYbIsWENM2VcjB0X7TawXbehL5I8OIsu2TgFS/nQCgZE94InrqMxrm7WDy+Lw==", "dependencies": { - "Microsoft.CodeCoverage": "17.0.0", - "Microsoft.TestPlatform.TestHost": "17.0.0" + "Microsoft.CodeCoverage": "17.2.0", + "Microsoft.TestPlatform.TestHost": "17.2.0" } }, "Moq": { "type": "Direct", - "requested": "[4.18.1, )", - "resolved": "4.18.1", - "contentHash": "MmZIKNyvn8VrivSaqA8tqy5DmwUievC9zsuNTrcb00oY4IeGq6fXT5BQK329lZ05/tyi5vp30AWe9fl0d2PZQg==", + "requested": "[4.18.2, )", + "resolved": "4.18.2", + "contentHash": "SjxKYS5nX6prcaT8ZjbkONh3vnh0Rxru09+gQ1a07v4TM530Oe/jq3Q4dOZPfo1wq0LYmTgLOZKrqRfEx4auPw==", "dependencies": { - "Castle.Core": "5.0.0", - "System.Threading.Tasks.Extensions": "4.5.4" + "Castle.Core": "5.1.0" } }, "Shouldly": { @@ -46,22 +45,31 @@ "System.Memory": "4.5.4" } }, + "System.Linq.Async": { + "type": "Direct", + "requested": "[6.0.1, )", + "resolved": "6.0.1", + "contentHash": "0YhHcaroWpQ9UCot3Pizah7ryAzQhNvobLMSxeDIGmnXfkQn8u5owvpOH0K6EVB+z9L7u6Cc4W17Br/+jyttEQ==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "6.0.0" + } + }, "xunit": { "type": "Direct", - "requested": "[2.4.1, )", - "resolved": "2.4.1", - "contentHash": "XNR3Yz9QTtec16O0aKcO6+baVNpXmOnPUxDkCY97J+8krUYxPvXT1szYYEUdKk4sB8GOI2YbAjRIOm8ZnXRfzQ==", + "requested": "[2.4.2, )", + "resolved": "2.4.2", + "contentHash": "6Mj73Ont3zj2CJuoykVJfE0ZmRwn7C+pTuRP8c4bnaaTFjwNG6tGe0prJ1yIbMe9AHrpDys63ctWacSsFJWK/w==", "dependencies": { - "xunit.analyzers": "0.10.0", - "xunit.assert": "[2.4.1]", - "xunit.core": "[2.4.1]" + "xunit.analyzers": "1.0.0", + "xunit.assert": "2.4.2", + "xunit.core": "[2.4.2]" } }, "Xunit.DependencyInjection": { "type": "Direct", - "requested": "[8.3.0, )", - "resolved": "8.3.0", - "contentHash": "uh4rHDT7IBpDB18zZWvP+jf7nbUYsGb71mHkeatNu9EvfTlY5MvtKGANBPwMEuxvnRhgypMSa14RhwunSvH5Ww==", + "requested": "[8.5.0, )", + "resolved": "8.5.0", + "contentHash": "OnSFB9x3MaXYFq9VFjdqoHgjOOjBOUxYFNkiQ3OXVe7I6r/KGs4yHJ3FAqZwddjNgKeRX1PEwiDWnDJOuonECQ==", "dependencies": { "Microsoft.Bcl.AsyncInterfaces": "1.0.0", "Microsoft.Extensions.Hosting": "2.1.0", @@ -71,23 +79,23 @@ }, "Xunit.DependencyInjection.Logging": { "type": "Direct", - "requested": "[8.0.0, )", - "resolved": "8.0.0", - "contentHash": "EfFGSxOGdu5k63+LBiPmG4rZ6kgTJF0WRES2MUriJ0LeLPD+0WJDNVjitx338O89ctt70gJ+JT9ogX4/74Esbg==", + "requested": "[8.0.1, )", + "resolved": "8.0.1", + "contentHash": "SXsc9Cp9LrpH3F9+35CbtCv0zuBw8491t3o5rK1/TVYeuwzVVR2h60/uGRYIs2GyVcKNRG7hOH8MbjPaap1sHQ==", "dependencies": { - "Xunit.DependencyInjection": "8.0.0" + "Xunit.DependencyInjection": "8.4.1" } }, "xunit.runner.visualstudio": { "type": "Direct", - "requested": "[2.4.3, )", - "resolved": "2.4.3", - "contentHash": "kZZSmOmKA8OBlAJaquPXnJJLM9RwQ27H7BMVqfMLUcTi9xHinWGJiWksa3D4NEtz0wZ/nxd2mogObvBgJKCRhQ==" + "requested": "[2.4.5, )", + "resolved": "2.4.5", + "contentHash": "OwHamvBdUKgqsXfBzWiCW/O98BTx81UKzx2bieIOQI7CZFE5NEQZGi8PBQGIKawDW96xeRffiNf20SjfC0x9hw==" }, "Castle.Core": { "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "edc8jjyXqzzy8jFdhs36FZdwmlDDTgqPb2Zy1Q5F/f2uAc88bu/VS/0Tpvgupmpl9zJOvOo5ZizVANb0ltN1NQ==", + "resolved": "5.1.0", + "contentHash": "31UJpTHOiWq95CDOHazE3Ub/hE/PydNWsJMwnEVTqFFP4WhAugwpaVGxzOxKgNeSUUeqS2W6lxV+q7u1pAOfXg==", "dependencies": { "System.Diagnostics.EventLog": "6.0.0" } @@ -109,6 +117,16 @@ "Microsoft.Win32.Registry": "5.0.0" } }, + "Docker.DotNet": { + "type": "Transitive", + "resolved": "3.125.10", + "contentHash": "sKu8AFiRPao1IqYPUT2mAxT0c7F+dgEfOonuVfgn5FYdHccHdL9Ge4Jsem0KHlxYzqE6QpOFDt1hR/J1XzqogQ==", + "dependencies": { + "Newtonsoft.Json": "13.0.1", + "System.Buffers": "4.5.1", + "System.Threading.Tasks.Extensions": "4.5.4" + } + }, "EmptyFiles": { "type": "Transitive", "resolved": "2.3.3", @@ -116,13 +134,13 @@ }, "Microsoft.Bcl.AsyncInterfaces": { "type": "Transitive", - "resolved": "1.0.0", - "contentHash": "K63Y4hORbBcKLWH5wnKgzyn7TOfYzevIEwIedQHBIkmkEBA9SCqgvom+XTuE+fAFGvINGkhFItaZ2dvMGdT5iw==" + "resolved": "6.0.0", + "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==" }, "Microsoft.CodeCoverage": { "type": "Transitive", - "resolved": "17.0.0", - "contentHash": "+B+09FPYBtf+cXfZOPIgpnP5mzLq5QdlBo+JEFy9CdqBaWHWE/YMY0Mos9uDsZhcgFegJm9GigAgMyqBZyfq+Q==" + "resolved": "17.2.0", + "contentHash": "MsKhJmwIfHxNDbTIlgQy29UpWSWPpbZOQPhQ7xalRy+ABnl8/neFHZGzSP3XlpW2dKAXHTFrtIcKzW/kopY2Bg==" }, "Microsoft.CSharp": { "type": "Transitive", @@ -224,8 +242,8 @@ }, "Microsoft.Extensions.Logging.Abstractions": { "type": "Transitive", - "resolved": "2.1.0", - "contentHash": "GfD2VtvN9z1W+m6pZZe98yh9VWTSdNY2dZSxtca9uFIY6aBI6twvskMvLO/ktClBOTQmAov/7Em+IWFlHepa0A==" + "resolved": "3.1.26", + "contentHash": "sCDtgEvfq0UhK6k9N7qCqvIsEud0T0eVu4UEW5G7urctFxRA8UUlcyrfFHH/k0tkEplZAv4EN8Xbj8j7BQNPhA==" }, "Microsoft.Extensions.Options": { "type": "Transitive", @@ -257,19 +275,19 @@ }, "Microsoft.TestPlatform.ObjectModel": { "type": "Transitive", - "resolved": "17.0.0", - "contentHash": "WMugCdPkA8U/BsSRc+3RN+DXcaYSDvp/s0MofVld08iF1O5fek4iKecygk6NruNf1rgJsv4LK71mrwbyeqhzHA==", + "resolved": "17.2.0", + "contentHash": "7j1KYDHLhU98XnCEbECMncXLydI9fNiFLcFsiBsP3lV6EkHOaj5kTPAWHYkKnPGRC9TbZUboSQq8rWI4dTQsxg==", "dependencies": { - "NuGet.Frameworks": "5.0.0", + "NuGet.Frameworks": "5.11.0", "System.Reflection.Metadata": "1.6.0" } }, "Microsoft.TestPlatform.TestHost": { "type": "Transitive", - "resolved": "17.0.0", - "contentHash": "xkKFzm0hylHF0SlDj78ACYMJC/i8fQ3i16sDDNYoKnjTsstGSQfuSBJ+QT4nqRXk/fOiYTh+iY0KIX5N7HTLuQ==", + "resolved": "17.2.0", + "contentHash": "bI67J+hers241h7eD2eecS02p9CbKcQDIeoRvO4FgMlTWg2ZTzc0D3uWLYr5U+K5x9O1pNmyMoMDbYIeWY/TWw==", "dependencies": { - "Microsoft.TestPlatform.ObjectModel": "17.0.0", + "Microsoft.TestPlatform.ObjectModel": "17.2.0", "Newtonsoft.Json": "9.0.1" } }, @@ -361,38 +379,38 @@ }, "MongoDB.Bson": { "type": "Transitive", - "resolved": "2.16.1", - "contentHash": "d647KTPQ7hWqJmvCg80iiVdm239llaUwMyIeRF/0zKpN+ddRWh9jT/g6R6WQrmi4qd7yodvv/Jn0rpEqh4QN8g==", + "resolved": "2.17.1", + "contentHash": "IBr5w6ygeUCTobiS4J2UlYeIsnjSJvOOf31g60EkRa3NIeyrYs7Y51HeOvJ8r6NPcKv1hLj8xwoop6hDTetAdA==", "dependencies": { "System.Runtime.CompilerServices.Unsafe": "5.0.0" } }, "MongoDB.Driver": { "type": "Transitive", - "resolved": "2.16.1", - "contentHash": "LqDWfRG7gM1tZKcG9Q/vuQGYF5GsBuxUF5KcOgvWrE6P7pSkOSL9xGZ7ABZ6XRVECGEQs+N6GyU1E4ViI4lh+g==", + "resolved": "2.17.1", + "contentHash": "A5Yvm3RUdkSYnvKWVb/bZfvhzG+L+t0n80JuUXf0p2QG1TbtqHE9hX/FBK+BoF7sw9rzUTw8VHYeqX5rT0rxdA==", "dependencies": { - "MongoDB.Bson": "2.16.1", - "MongoDB.Driver.Core": "2.16.1", - "MongoDB.Libmongocrypt": "1.5.3" + "MongoDB.Bson": "2.17.1", + "MongoDB.Driver.Core": "2.17.1", + "MongoDB.Libmongocrypt": "1.5.5" } }, "MongoDB.Driver.Core": { "type": "Transitive", - "resolved": "2.16.1", - "contentHash": "oJZnXHnAyTd/haHYdbfKMRmPEZ1fFrndv8xhorHeTkUDeGgsPA89vpGMHcjppUyHMYBpLgHbn6GoMkleHKsTHg==", + "resolved": "2.17.1", + "contentHash": "lfuuQvCXcco6mG096PL8xRO+dBdHsDTR3DiYfK/ICHgFlL5RfKlBuE0xClEGKtaZ4Spe28/fF/GUcrrA/yfoAQ==", "dependencies": { "DnsClient": "1.6.1", - "MongoDB.Bson": "2.16.1", - "MongoDB.Libmongocrypt": "1.5.3", + "MongoDB.Bson": "2.17.1", + "MongoDB.Libmongocrypt": "1.5.5", "SharpCompress": "0.30.1", "System.Buffers": "4.5.1" } }, "MongoDB.Libmongocrypt": { "type": "Transitive", - "resolved": "1.5.3", - "contentHash": "OWWxuyuxbjAmOLPoaoUEYnIW4F7qexS6XYOdu6absxyGAqLBWEY+M4WY2Y0km2UUG1+QOPdebpb/7cg5BIEbdw==" + "resolved": "1.5.5", + "contentHash": "0DV4l2PjXirSJHD/b+LpOK3IfUDvkbpvvZBM2w1aYL6E/4vbhfyr/FP5laDNx2zRylqN1hIZO+EL7NgO/5GpVg==" }, "NETStandard.Library": { "type": "Transitive", @@ -447,37 +465,21 @@ }, "Newtonsoft.Json": { "type": "Transitive", - "resolved": "9.0.1", - "contentHash": "U82mHQSKaIk+lpSVCbWYKNavmNH1i5xrExDEquU1i6I5pV6UMOqRnJRSlKO3cMPfcpp0RgDY+8jUXHdQ4IfXvw==", - "dependencies": { - "Microsoft.CSharp": "4.0.1", - "System.Collections": "4.0.11", - "System.Diagnostics.Debug": "4.0.11", - "System.Dynamic.Runtime": "4.0.11", - "System.Globalization": "4.0.11", - "System.IO": "4.1.0", - "System.Linq": "4.1.0", - "System.Linq.Expressions": "4.1.0", - "System.ObjectModel": "4.0.12", - "System.Reflection": "4.1.0", - "System.Reflection.Extensions": "4.0.1", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0", - "System.Runtime.Extensions": "4.1.0", - "System.Runtime.Serialization.Primitives": "4.1.1", - "System.Text.Encoding": "4.0.11", - "System.Text.Encoding.Extensions": "4.0.11", - "System.Text.RegularExpressions": "4.1.0", - "System.Threading": "4.0.11", - "System.Threading.Tasks": "4.0.11", - "System.Xml.ReaderWriter": "4.0.11", - "System.Xml.XDocument": "4.0.11" + "resolved": "13.0.1", + "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==" + }, + "Npgsql": { + "type": "Transitive", + "resolved": "6.0.6", + "contentHash": "IIwnoJp0sFkhAydT/KKe/0NhlJKhYPIrXSE95AuU/2dqHNI9alxvjClJSGL+QE8NGqq1SFn+NenxVtm/JYsrJg==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0" } }, "NuGet.Frameworks": { "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "c5JVjuVAm4f7E9Vj+v09Z9s2ZsqFDjBpcsyS3M9xRo0bEdm/LVZSzLxxNvfvAwRiiE8nwe1h2G4OwiwlzFKXlA==" + "resolved": "5.11.0", + "contentHash": "eaiXkUjC4NPcquGWzAGMXjuxvLwc6XGKMptSyOGQeT0X70BUZObuybJFZLA0OfTdueLd3US23NBPTBb6iF3V1Q==" }, "Pipelines.Sockets.Unofficial": { "type": "Transitive", @@ -655,6 +657,11 @@ "resolved": "0.30.1", "contentHash": "XqD4TpfyYGa7QTPzaGlMVbcecKnXy4YmYLDWrU+JIj7IuRNl7DH2END+Ll7ekWIY8o3dAMWLFDE1xdhfIWD1nw==" }, + "SharpZipLib": { + "type": "Transitive", + "resolved": "1.3.3", + "contentHash": "N8+hwhsKZm25tDJfWpBSW7EGhH/R7EMuiX+KJ4C4u+fCWVc1lJ5zg1u3S1RPPVYgTqhx/C3hxrqUpi6RwK5+Tg==" + }, "StackExchange.Redis": { "type": "Transitive", "resolved": "2.6.48", @@ -888,28 +895,6 @@ "Microsoft.Win32.SystemEvents": "5.0.0" } }, - "System.Dynamic.Runtime": { - "type": "Transitive", - "resolved": "4.0.11", - "contentHash": "db34f6LHYM0U0JpE+sOmjar27BnqTVkbLJhgfwMpTdgTigG/Hna3m2MYVwnFzGGKnEJk2UXFuoVTr8WUbU91/A==", - "dependencies": { - "System.Collections": "4.0.11", - "System.Diagnostics.Debug": "4.0.11", - "System.Globalization": "4.0.11", - "System.Linq": "4.1.0", - "System.Linq.Expressions": "4.1.0", - "System.ObjectModel": "4.0.12", - "System.Reflection": "4.1.0", - "System.Reflection.Emit": "4.0.1", - "System.Reflection.Emit.ILGeneration": "4.0.1", - "System.Reflection.Primitives": "4.0.1", - "System.Reflection.TypeExtensions": "4.1.0", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0", - "System.Runtime.Extensions": "4.1.0", - "System.Threading": "4.0.11" - } - }, "System.Formats.Asn1": { "type": "Transitive", "resolved": "5.0.0", @@ -1353,15 +1338,6 @@ "System.Runtime.Extensions": "4.3.0" } }, - "System.Runtime.Serialization.Primitives": { - "type": "Transitive", - "resolved": "4.1.1", - "contentHash": "HZ6Du5QrTG8MNJbf4e4qMO3JRAkIboGT5Fk804uZtg3Gq516S7hAqTm2UZKUHa7/6HUGdVy3AqMQKbns06G/cg==", - "dependencies": { - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0" - } - }, "System.Security.AccessControl": { "type": "Transitive", "resolved": "5.0.0", @@ -1628,6 +1604,11 @@ "System.Text.Encoding": "4.3.0" } }, + "System.Text.Json": { + "type": "Transitive", + "resolved": "4.7.2", + "contentHash": "TcMd95wcrubm9nHvJEQs70rC0H/8omiSGGpU4FQ/ZA1URIqD4pjmFJh2Mfv1yH1eHgJDWTi2hMDXwTET+zOOyg==" + }, "System.Text.RegularExpressions": { "type": "Transitive", "resolved": "4.3.0", @@ -1728,6 +1709,18 @@ "System.Xml.ReaderWriter": "4.3.0" } }, + "Testcontainers": { + "type": "Transitive", + "resolved": "2.1.0", + "contentHash": "ESpfTlnntNJfPoQ2gg/lNt2S+SuFAI7XYISfNWWKrroVOuJKGq/HsXQVA9Yj/n+fQ8TgpbMyGGiwZGxkbbVAKA==", + "dependencies": { + "Docker.DotNet": "3.125.10", + "Microsoft.Bcl.AsyncInterfaces": "1.1.1", + "Microsoft.Extensions.Logging.Abstractions": "3.1.26", + "SharpZipLib": "1.3.3", + "System.Text.Json": "4.7.2" + } + }, "xunit.abstractions": { "type": "Transitive", "resolved": "2.0.3", @@ -1735,30 +1728,30 @@ }, "xunit.analyzers": { "type": "Transitive", - "resolved": "0.10.0", - "contentHash": "4/IDFCJfIeg6bix9apmUtIMwvOsiwqdEexeO/R2D4GReIGPLIRODTpId/l4LRSrAJk9lEO3Zx1H0Zx6uohJDNg==" + "resolved": "1.0.0", + "contentHash": "BeO8hEgs/c8Ls2647fPfieMngncvf0D0xYNDfIO59MolxtCtVjFRd6SRc+7tj8VMqkVOuJcnc9eh4ngI2cAmLQ==" }, "xunit.assert": { "type": "Transitive", - "resolved": "2.4.1", - "contentHash": "O/Oe0BS5RmSsM+LQOb041TzuPo5MdH2Rov+qXGS37X+KFG1Hxz7kopYklM5+1Y+tRGeXrOx5+Xne1RuqLFQoyQ==", + "resolved": "2.4.2", + "contentHash": "pxJISOFjn2XTTi1mcDCkRZrTFb9OtRRCtx2kZFNF51GdReLr1ls2rnyxvAS4JO247K3aNtflvh5Q0346K5BROA==", "dependencies": { "NETStandard.Library": "1.6.1" } }, "xunit.core": { "type": "Transitive", - "resolved": "2.4.1", - "contentHash": "Zsj5OMU6JasNGERXZy8s72+pcheG6Q15atS5XpZXqAtULuyQiQ6XNnUsp1gyfC6WgqScqMvySiEHmHcOG6Eg0Q==", + "resolved": "2.4.2", + "contentHash": "KB4yGCxNqIVyekhJLXtKSEq6BaXVp/JO3mbGVE1hxypZTLEe7h+sTbAhpA+yZW2dPtXTuiW+C1B2oxxHEkrmOw==", "dependencies": { - "xunit.extensibility.core": "[2.4.1]", - "xunit.extensibility.execution": "[2.4.1]" + "xunit.extensibility.core": "[2.4.2]", + "xunit.extensibility.execution": "[2.4.2]" } }, "xunit.extensibility.core": { "type": "Transitive", - "resolved": "2.4.1", - "contentHash": "yKZKm/8QNZnBnGZFD9SewkllHBiK0DThybQD/G4PiAmQjKtEZyHi6ET70QPU9KtSMJGRYS6Syk7EyR2EVDU4Kg==", + "resolved": "2.4.2", + "contentHash": "W1BoXTIN1C6kpVSMw25huSet25ky6IAQUNovu3zGOGN/jWnbgSoTyCrlIhmXSg0tH5nEf8q7h3OjNHOjyu5PfA==", "dependencies": { "NETStandard.Library": "1.6.1", "xunit.abstractions": "2.0.3" @@ -1766,49 +1759,65 @@ }, "xunit.extensibility.execution": { "type": "Transitive", - "resolved": "2.4.1", - "contentHash": "7e/1jqBpcb7frLkB6XDrHCGXAbKN4Rtdb88epYxCSRQuZDRW8UtTfdTEVpdTl8s4T56e07hOBVd4G0OdCxIY2A==", + "resolved": "2.4.2", + "contentHash": "CZmgcKkwpyo8FlupZdWpJCryrAOWLh1FBPG6gmVZuPQkGQsim/oL4PcP4nfrC2hHgXUFtluvaJ0Sp9PQKUMNpg==", "dependencies": { "NETStandard.Library": "1.6.1", - "xunit.extensibility.core": "[2.4.1]" + "xunit.extensibility.core": "[2.4.2]" } }, "entitydb.abstractions": { - "type": "Project" + "type": "Project", + "dependencies": { + "System.Linq.Async": "6.0.1" + } }, "entitydb.common": { "type": "Project", "dependencies": { - "EntityDb.Abstractions": "1.0.0" + "EntityDb.Abstractions": "1.0.0", + "System.Linq.Async": "6.0.1" } }, "entitydb.common.tests": { "type": "Project", "dependencies": { - "Bogus": "34.0.1", + "Bogus": "34.0.2", "EntityDb.Common": "1.0.0", "EntityDb.InMemory": "1.0.0", "EntityDb.MongoDb.Provisioner": "1.0.0", + "EntityDb.Npgsql.Provisioner": "1.0.0", "EntityDb.Redis": "1.0.0", - "Microsoft.NET.Test.Sdk": "17.0.0", - "Moq": "4.18.1", + "Microsoft.NET.Test.Sdk": "17.2.0", + "Moq": "4.18.2", "Shouldly": "4.0.3", - "Xunit.DependencyInjection": "8.3.0", - "Xunit.DependencyInjection.Logging": "8.0.0", - "xunit": "2.4.1" + "System.Linq.Async": "6.0.1", + "Testcontainers": "2.1.0", + "Xunit.DependencyInjection": "8.5.0", + "Xunit.DependencyInjection.Logging": "8.0.1", + "xunit": "2.4.2" } }, "entitydb.inmemory": { "type": "Project", "dependencies": { - "EntityDb.Common": "1.0.0" + "EntityDb.Common": "1.0.0", + "System.Linq.Async": "6.0.1" + } + }, + "entitydb.json": { + "type": "Project", + "dependencies": { + "EntityDb.Common": "1.0.0", + "System.Linq.Async": "6.0.1" } }, "entitydb.mongodb": { "type": "Project", "dependencies": { "EntityDb.Common": "1.0.0", - "MongoDB.Driver": "2.16.1" + "MongoDB.Driver": "2.17.1", + "System.Linq.Async": "6.0.1" } }, "entitydb.mongodb.provisioner": { @@ -1816,14 +1825,42 @@ "dependencies": { "EntityDb.MongoDb": "1.0.0", "System.CommandLine": "2.0.0-beta4.22272.1", - "System.CommandLine.NamingConventionBinder": "2.0.0-beta4.22272.1" + "System.CommandLine.NamingConventionBinder": "2.0.0-beta4.22272.1", + "System.Linq.Async": "6.0.1" + } + }, + "entitydb.npgsql": { + "type": "Project", + "dependencies": { + "EntityDb.SqlDb": "1.0.0", + "Npgsql": "6.0.6", + "System.Linq.Async": "6.0.1" + } + }, + "entitydb.npgsql.provisioner": { + "type": "Project", + "dependencies": { + "EntityDb.Npgsql": "1.0.0", + "System.CommandLine": "2.0.0-beta4.22272.1", + "System.CommandLine.NamingConventionBinder": "2.0.0-beta4.22272.1", + "System.Linq.Async": "6.0.1" } }, "entitydb.redis": { "type": "Project", "dependencies": { "EntityDb.Common": "1.0.0", - "StackExchange.Redis": "2.6.48" + "EntityDb.Json": "1.0.0", + "StackExchange.Redis": "2.6.48", + "System.Linq.Async": "6.0.1" + } + }, + "entitydb.sqldb": { + "type": "Project", + "dependencies": { + "EntityDb.Common": "1.0.0", + "EntityDb.Json": "1.0.0", + "System.Linq.Async": "6.0.1" } } } diff --git a/test/docker-compose.yml b/test/docker-compose.yml deleted file mode 100644 index d88b9800..00000000 --- a/test/docker-compose.yml +++ /dev/null @@ -1,13 +0,0 @@ -version: "3.3" -services: - redis: - image: redis:7.0.2 - ports: - - "6379:6379" - mongodb: - image: mongo:5.0.9 - ports: - - "27017:27017" - volumes: - - ./mongod-scripts:/docker-entrypoint-initdb.d/ - command: --replSet entitydb \ No newline at end of file