From 27c1999081f40b6c76783265715dc2920a06ccee Mon Sep 17 00:00:00 2001 From: erikoijwall <46994303+erikoijwall@users.noreply.github.com> Date: Mon, 18 Dec 2023 16:08:22 +0100 Subject: [PATCH] Add support in DomainServiceTestHost for asynchronous queries that return a single entity (#464) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add support in DomainServiceTestHost for asynchronous queries * QuerySingleAsync with two overloads Expression>, Expression>> queryOperation * Added overload for TryQuerySingle to handle async query * update comment * review fixes --------- Co-authored-by: Erik Ă–ijwall --- .../Framework/DomainServiceTestHost.cs | 51 +++++++++++++++ .../Test/DomainServiceTestHostTests.cs | 40 ++++++++++++ .../Baselines/Default/Cities/Cities.g.cs | 63 ++++++++++++++++++- .../Baselines/Default/Cities/Cities.g.vb | 61 +++++++++++++++++- .../Cities/CityDomainService.cs | 12 ++++ 5 files changed, 225 insertions(+), 2 deletions(-) diff --git a/src/OpenRiaServices.Server.UnitTesting/Framework/DomainServiceTestHost.cs b/src/OpenRiaServices.Server.UnitTesting/Framework/DomainServiceTestHost.cs index 5ba650404..4daf38c17 100644 --- a/src/OpenRiaServices.Server.UnitTesting/Framework/DomainServiceTestHost.cs +++ b/src/OpenRiaServices.Server.UnitTesting/Framework/DomainServiceTestHost.cs @@ -265,6 +265,37 @@ public TEntity QuerySingle(Expression> qu return this.QueryCore(queryOperation).SingleOrDefault(); } + + /// + /// Invokes the specified asynchronously and returns the result + /// + /// + /// This method should be used for query signatures that do no return a collection + /// + /// The type of entity to return + /// The identifying the query operation to invoke + /// The entity returned from the specified operation + /// is thrown if there are any validation errors + public async Task QuerySingleAsync(Expression> queryOperation, CancellationToken ct = default) where TEntity : class + { + return (await this.QueryCoreAsync(queryOperation, ct)).SingleOrDefault(); + } + + /// + /// Invokes the specified asynchronously and returns the result + /// + /// + /// This method should be used for query signatures that do no return a collection + /// + /// The type of entity to return + /// The identifying the query operation to invoke + /// The entity returned from the specified operation + /// is thrown if there are any validation errors + public async Task QuerySingleAsync(Expression>> queryOperation, CancellationToken ct = default) where TEntity : class + { + return (await this.QueryCoreAsync(queryOperation, ct)).SingleOrDefault(); + } + /// /// Invokes the specified and returns the results, the validation errors, /// and whether the operation completed successfully @@ -299,6 +330,26 @@ public bool TryQuerySingle(Expression> qu return success; } + /// + /// Invokes the specified and returns the result, the validation errors, + /// and whether the operation completed successfully + /// + /// + /// This method should be used for query signatures that do no return a collection + /// + /// The type of entity in the result + /// The identifying the query operation to invoke + /// The entity returned from the specified operation + /// The validation errors that occurred + /// Whether the operation completed without error + public bool TryQuerySingle(Expression>> queryOperation, out TEntity result, out IList validationErrors) where TEntity : class + { + IEnumerable results; + bool success = this.TryQueryCore(queryOperation, out results, out validationErrors); + result = (results == null) ? null : results.SingleOrDefault(); + return success; + } + #endregion #region Insert diff --git a/src/OpenRiaServices.Server.UnitTesting/Test/DomainServiceTestHostTests.cs b/src/OpenRiaServices.Server.UnitTesting/Test/DomainServiceTestHostTests.cs index 6352f56eb..e7f804e61 100644 --- a/src/OpenRiaServices.Server.UnitTesting/Test/DomainServiceTestHostTests.cs +++ b/src/OpenRiaServices.Server.UnitTesting/Test/DomainServiceTestHostTests.cs @@ -154,6 +154,46 @@ public async Task IEnumerableQueryAsync() Assert.AreEqual(3, result.Count()); } + [TestMethod] + public async Task QuerySingleAsync() + { + var testHost = new DomainServiceTestHost(); + + var result = await testHost.QuerySingleAsync(s => s.GetZipByFourDigitCodeAsync(8625), CancellationToken.None); + + Assert.IsNotNull(result); + } + + [TestMethod] + public async Task QuerySingleAsyncWithSynchronousQuery() + { + var testHost = new DomainServiceTestHost(); + + var result = await testHost.QuerySingleAsync(s => s.GetZipByFourDigitCode2(8625), CancellationToken.None); + + Assert.IsNotNull(result); + } + + [TestMethod] + public void TryQuerySingleTaskOverload() + { + var testHost = new DomainServiceTestHost(); + + testHost.TryQuerySingle(s => s.GetZipByFourDigitCodeAsync(8625), out Zip result, out var validationErrors); + + Assert.IsNotNull(result); + } + + [TestMethod] + public void TryQuerySingle() + { + var testHost = new DomainServiceTestHost(); + + testHost.TryQuerySingle(s => s.GetZipByFourDigitCode2(8625), out Zip result, out var validationErrors); + + Assert.IsNotNull(result); + } + [TestMethod] public async Task SubmitAsync() { diff --git a/src/Test/Desktop/OpenRiaServices.Common.DomainServices.Test/Baselines/Default/Cities/Cities.g.cs b/src/Test/Desktop/OpenRiaServices.Common.DomainServices.Test/Baselines/Default/Cities/Cities.g.cs index 66defce02..35be6e93b 100644 --- a/src/Test/Desktop/OpenRiaServices.Common.DomainServices.Test/Baselines/Default/Cities/Cities.g.cs +++ b/src/Test/Desktop/OpenRiaServices.Common.DomainServices.Test/Baselines/Default/Cities/Cities.g.cs @@ -1,7 +1,6 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -635,6 +634,32 @@ public EntityQuery GetStatesInShippingZoneQuery(ShippingZone shippingZone return base.CreateQuery("GetStatesInShippingZone", parameters, false, true); } + /// + /// Gets an EntityQuery instance that can be used to load entity instances using the 'GetZipByFourDigitCode' query. + /// + /// The value for the 'fourDigitCode' parameter of the query. + /// An EntityQuery that can be loaded to retrieve entity instances. + public EntityQuery GetZipByFourDigitCodeQuery(int fourDigitCode) + { + Dictionary parameters = new Dictionary(); + parameters.Add("fourDigitCode", fourDigitCode); + this.ValidateMethod("GetZipByFourDigitCodeQuery", parameters); + return base.CreateQuery("GetZipByFourDigitCode", parameters, false, false); + } + + /// + /// Gets an EntityQuery instance that can be used to load entity instances using the 'GetZipByFourDigitCode2' query. + /// + /// The value for the 'fourDigitCode' parameter of the query. + /// An EntityQuery that can be loaded to retrieve entity instances. + public EntityQuery GetZipByFourDigitCode2Query(int fourDigitCode) + { + Dictionary parameters = new Dictionary(); + parameters.Add("fourDigitCode", fourDigitCode); + this.ValidateMethod("GetZipByFourDigitCode2Query", parameters); + return base.CreateQuery("GetZipByFourDigitCode2", parameters, false, false); + } + /// /// Gets an EntityQuery instance that can be used to load entity instances using the 'GetZips' query. /// @@ -1175,6 +1200,42 @@ public interface ICityDomainServiceContract /// The 'QueryResult' returned from the 'GetStatesInShippingZone' operation. QueryResult EndGetStatesInShippingZone(IAsyncResult result); + /// + /// Asynchronously invokes the 'GetZipByFourDigitCode' operation. + /// + /// The value for the 'fourDigitCode' parameter of this action. + /// Callback to invoke on completion. + /// Optional state object. + /// An IAsyncResult that can be used to monitor the request. + [HasSideEffects(false)] + [OperationContract(AsyncPattern=true, Action="http://tempuri.org/CityDomainService/GetZipByFourDigitCode", ReplyAction="http://tempuri.org/CityDomainService/GetZipByFourDigitCodeResponse")] + IAsyncResult BeginGetZipByFourDigitCode(int fourDigitCode, AsyncCallback callback, object asyncState); + + /// + /// Completes the asynchronous operation begun by 'BeginGetZipByFourDigitCode'. + /// + /// The IAsyncResult returned from 'BeginGetZipByFourDigitCode'. + /// The 'QueryResult' returned from the 'GetZipByFourDigitCode' operation. + QueryResult EndGetZipByFourDigitCode(IAsyncResult result); + + /// + /// Asynchronously invokes the 'GetZipByFourDigitCode2' operation. + /// + /// The value for the 'fourDigitCode' parameter of this action. + /// Callback to invoke on completion. + /// Optional state object. + /// An IAsyncResult that can be used to monitor the request. + [HasSideEffects(false)] + [OperationContract(AsyncPattern=true, Action="http://tempuri.org/CityDomainService/GetZipByFourDigitCode2", ReplyAction="http://tempuri.org/CityDomainService/GetZipByFourDigitCode2Response")] + IAsyncResult BeginGetZipByFourDigitCode2(int fourDigitCode, AsyncCallback callback, object asyncState); + + /// + /// Completes the asynchronous operation begun by 'BeginGetZipByFourDigitCode2'. + /// + /// The IAsyncResult returned from 'BeginGetZipByFourDigitCode2'. + /// The 'QueryResult' returned from the 'GetZipByFourDigitCode2' operation. + QueryResult EndGetZipByFourDigitCode2(IAsyncResult result); + /// /// Asynchronously invokes the 'GetZips' operation. /// diff --git a/src/Test/Desktop/OpenRiaServices.Common.DomainServices.Test/Baselines/Default/Cities/Cities.g.vb b/src/Test/Desktop/OpenRiaServices.Common.DomainServices.Test/Baselines/Default/Cities/Cities.g.vb index d829dc918..7a96b090c 100644 --- a/src/Test/Desktop/OpenRiaServices.Common.DomainServices.Test/Baselines/Default/Cities/Cities.g.vb +++ b/src/Test/Desktop/OpenRiaServices.Common.DomainServices.Test/Baselines/Default/Cities/Cities.g.vb @@ -1,7 +1,6 @@ '------------------------------------------------------------------------------ ' ' This code was generated by a tool. -' Runtime Version:4.0.30319.42000 ' ' Changes to this file may cause incorrect behavior and will be lost if ' the code is regenerated. @@ -581,6 +580,30 @@ Namespace Cities Return MyBase.CreateQuery(Of State)("GetStatesInShippingZone", parameters, false, true) End Function + ''' + ''' Gets an EntityQuery instance that can be used to load entity instances using the 'GetZipByFourDigitCode' query. + ''' + ''' The value for the 'fourDigitCode' parameter of the query. + ''' An EntityQuery that can be loaded to retrieve entity instances. + Public Function GetZipByFourDigitCodeQuery(ByVal fourDigitCode As Integer) As EntityQuery(Of Zip) + Dim parameters As Dictionary(Of String, Object) = New Dictionary(Of String, Object)() + parameters.Add("fourDigitCode", fourDigitCode) + Me.ValidateMethod("GetZipByFourDigitCodeQuery", parameters) + Return MyBase.CreateQuery(Of Zip)("GetZipByFourDigitCode", parameters, false, false) + End Function + + ''' + ''' Gets an EntityQuery instance that can be used to load entity instances using the 'GetZipByFourDigitCode2' query. + ''' + ''' The value for the 'fourDigitCode' parameter of the query. + ''' An EntityQuery that can be loaded to retrieve entity instances. + Public Function GetZipByFourDigitCode2Query(ByVal fourDigitCode As Integer) As EntityQuery(Of Zip) + Dim parameters As Dictionary(Of String, Object) = New Dictionary(Of String, Object)() + parameters.Add("fourDigitCode", fourDigitCode) + Me.ValidateMethod("GetZipByFourDigitCode2Query", parameters) + Return MyBase.CreateQuery(Of Zip)("GetZipByFourDigitCode2", parameters, false, false) + End Function + ''' ''' Gets an EntityQuery instance that can be used to load entity instances using the 'GetZips' query. ''' @@ -1091,6 +1114,42 @@ Namespace Cities ''' The 'QueryResult' returned from the 'GetStatesInShippingZone' operation. Function EndGetStatesInShippingZone(ByVal result As IAsyncResult) As QueryResult(Of State) + ''' + ''' Asynchronously invokes the 'GetZipByFourDigitCode' operation. + ''' + ''' The value for the 'fourDigitCode' parameter of this action. + ''' Callback to invoke on completion. + ''' Optional state object. + ''' An IAsyncResult that can be used to monitor the request. + _ + Function BeginGetZipByFourDigitCode(ByVal fourDigitCode As Integer, ByVal callback As AsyncCallback, ByVal asyncState As Object) As IAsyncResult + + ''' + ''' Completes the asynchronous operation begun by 'BeginGetZipByFourDigitCode'. + ''' + ''' The IAsyncResult returned from 'BeginGetZipByFourDigitCode'. + ''' The 'QueryResult' returned from the 'GetZipByFourDigitCode' operation. + Function EndGetZipByFourDigitCode(ByVal result As IAsyncResult) As QueryResult(Of Zip) + + ''' + ''' Asynchronously invokes the 'GetZipByFourDigitCode2' operation. + ''' + ''' The value for the 'fourDigitCode' parameter of this action. + ''' Callback to invoke on completion. + ''' Optional state object. + ''' An IAsyncResult that can be used to monitor the request. + _ + Function BeginGetZipByFourDigitCode2(ByVal fourDigitCode As Integer, ByVal callback As AsyncCallback, ByVal asyncState As Object) As IAsyncResult + + ''' + ''' Completes the asynchronous operation begun by 'BeginGetZipByFourDigitCode2'. + ''' + ''' The IAsyncResult returned from 'BeginGetZipByFourDigitCode2'. + ''' The 'QueryResult' returned from the 'GetZipByFourDigitCode2' operation. + Function EndGetZipByFourDigitCode2(ByVal result As IAsyncResult) As QueryResult(Of Zip) + ''' ''' Asynchronously invokes the 'GetZips' operation. ''' diff --git a/src/Test/Desktop/OpenRiaServices.Common.DomainServices.Test/Cities/CityDomainService.cs b/src/Test/Desktop/OpenRiaServices.Common.DomainServices.Test/Cities/CityDomainService.cs index 7bf65970e..37d506a58 100644 --- a/src/Test/Desktop/OpenRiaServices.Common.DomainServices.Test/Cities/CityDomainService.cs +++ b/src/Test/Desktop/OpenRiaServices.Common.DomainServices.Test/Cities/CityDomainService.cs @@ -135,6 +135,18 @@ public async Task> GetZipsAsEnumerable() return await Task.FromResult(GetZips()); } + [Query(IsComposable = false)] + public Task GetZipByFourDigitCodeAsync(int fourDigitCode) + { + return Task.FromResult(GetZipByFourDigitCode2(fourDigitCode)); + } + + [Query(IsComposable = false)] + public Zip GetZipByFourDigitCode2(int fourDigitCode) + { + return GetZips().Single(z => z.FourDigit == fourDigitCode); + } + [Query] public async Task> GetZipsWithDelay(TimeSpan delay) {