diff --git a/sdk/src/Services/DynamoDBv2/Custom/DataModel/AsyncSearch.cs b/sdk/src/Services/DynamoDBv2/Custom/DataModel/AsyncSearch.cs index e08008c8dc50..159c1281be09 100644 --- a/sdk/src/Services/DynamoDBv2/Custom/DataModel/AsyncSearch.cs +++ b/sdk/src/Services/DynamoDBv2/Custom/DataModel/AsyncSearch.cs @@ -13,18 +13,38 @@ * permissions and limitations under the License. */ -using Amazon.DynamoDBv2.DataModel; using Amazon.DynamoDBv2.DocumentModel; namespace Amazon.DynamoDBv2.DataModel { + /// + /// Interface retrieving search results (Query or Scan) + /// from DynamoDB. + /// + public partial interface IAsyncSearch + { + /// + /// Flag that, if true, indicates that the search is done + /// + bool IsDone { get; } + + /// + /// Pagination token corresponding to the item where the search operation stopped, + /// inclusive of the previous result set. Use this value to start a new + /// operation to resume search from the next item. + /// + string PaginationToken { get; } + } + /// /// A strongly-typed object for retrieving search results (Query or Scan) /// from DynamoDB. /// - public partial class AsyncSearch + public partial class AsyncSearch : IAsyncSearch { - #region Constructor + private Search _documentSearch { get; set; } + private DynamoDBContext _sourceContext { get; set; } + private DynamoDBFlatConfig _config { get; set; } /// /// This constructor is used for mocking. Users that want to mock AsyncSearch can create a subclass of AsyncSearch and make a public parameterless constructor. @@ -36,47 +56,27 @@ protected AsyncSearch() internal AsyncSearch(DynamoDBContext source, DynamoDBContext.ContextSearch contextSearch) { - SourceContext = source; - DocumentSearch = contextSearch.Search; - Config = contextSearch.FlatConfig; + _sourceContext = source; + _documentSearch = contextSearch.Search; + _config = contextSearch.FlatConfig; } - #endregion - - #region Private members - - private Search DocumentSearch { get; set; } - private DynamoDBContext SourceContext { get; set; } - private DynamoDBFlatConfig Config { get; set; } - - #endregion - - #region Public properties - - /// - /// Flag that, if true, indicates that the search is done - /// + /// public virtual bool IsDone { get { - return DocumentSearch.IsDone; + return _documentSearch.IsDone; } } - /// - /// Pagination token corresponding to the item where the search operation stopped, - /// inclusive of the previous result set. Use this value to start a new - /// operation to resume search from the next item. - /// + /// public virtual string PaginationToken { get { - return DocumentSearch.PaginationToken; + return _documentSearch.PaginationToken; } } - - #endregion } } diff --git a/sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/AsyncSearch.Async.cs b/sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/AsyncSearch.Async.cs index 8945c588fabd..c37d83a73c6d 100644 --- a/sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/AsyncSearch.Async.cs +++ b/sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/AsyncSearch.Async.cs @@ -18,21 +18,10 @@ using System.Threading; using System.Threading.Tasks; -using Amazon.Runtime.Internal; -using Amazon.DynamoDBv2.DocumentModel; -using Amazon.DynamoDBv2.DataModel; - namespace Amazon.DynamoDBv2.DataModel { - /// - /// A strongly-typed object for retrieving search results (Query or Scan) - /// from DynamoDB. - /// - /// - public partial class AsyncSearch + public partial interface IAsyncSearch { - #region Async public - /// /// Initiates the asynchronous execution to get the next set of results from DynamoDB. /// @@ -45,12 +34,7 @@ public partial class AsyncSearch /// A Task that can be used to poll or wait for results, or both. /// Results will include the next set of result items from DynamoDB. /// - public virtual async Task> GetNextSetAsync(CancellationToken cancellationToken = default(CancellationToken)) - { - var documents = await DocumentSearch.GetNextSetHelperAsync(cancellationToken).ConfigureAwait(false); - List items = SourceContext.FromDocumentsHelper(documents, this.Config).ToList(); - return items; - } + Task> GetNextSetAsync(CancellationToken cancellationToken = default(CancellationToken)); /// /// Initiates the asynchronous execution to get all the remaining results from DynamoDB. @@ -60,13 +44,25 @@ public partial class AsyncSearch /// A Task that can be used to poll or wait for results, or both. /// Results will include the remaining result items from DynamoDB. /// - public virtual async Task> GetRemainingAsync(CancellationToken cancellationToken = default(CancellationToken)) + Task> GetRemainingAsync(CancellationToken cancellationToken = default(CancellationToken)); + } + + public partial class AsyncSearch : IAsyncSearch + { + /// + public virtual async Task> GetNextSetAsync(CancellationToken cancellationToken = default(CancellationToken)) { - var documents = await DocumentSearch.GetRemainingHelperAsync(cancellationToken).ConfigureAwait(false); - List items = SourceContext.FromDocumentsHelper(documents, this.Config).ToList(); + var documents = await _documentSearch.GetNextSetHelperAsync(cancellationToken).ConfigureAwait(false); + List items = _sourceContext.FromDocumentsHelper(documents, this._config).ToList(); return items; } - #endregion + /// + public virtual async Task> GetRemainingAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var documents = await _documentSearch.GetRemainingHelperAsync(cancellationToken).ConfigureAwait(false); + List items = _sourceContext.FromDocumentsHelper(documents, this._config).ToList(); + return items; + } } } diff --git a/sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/Context.Async.cs b/sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/Context.Async.cs index a408abb50e5a..05bc235e6a7c 100644 --- a/sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/Context.Async.cs +++ b/sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/Context.Async.cs @@ -256,7 +256,7 @@ public Task ExecuteBatchGetAsync(params IBatchGet[] batches) #region Scan async /// - public AsyncSearch ScanAsync(IEnumerable conditions) + public IAsyncSearch ScanAsync(IEnumerable conditions) { var scan = ConvertScan(conditions, null); return FromSearchAsync(scan); @@ -264,21 +264,21 @@ public AsyncSearch ScanAsync(IEnumerable conditions) /// [Obsolete("Use the ScanAsync overload that takes ScanConfig instead, since DynamoDBOperationConfig contains properties that are not applicable to ScanAsync.")] - public AsyncSearch ScanAsync(IEnumerable conditions, DynamoDBOperationConfig operationConfig = null) + public IAsyncSearch ScanAsync(IEnumerable conditions, DynamoDBOperationConfig operationConfig = null) { var scan = ConvertScan(conditions, operationConfig); return FromSearchAsync(scan); } /// - public AsyncSearch ScanAsync(IEnumerable conditions, ScanConfig scanConfig) + public IAsyncSearch ScanAsync(IEnumerable conditions, ScanConfig scanConfig) { var scan = ConvertScan(conditions, scanConfig?.ToDynamoDBOperationConfig()); return FromSearchAsync(scan); } /// - public AsyncSearch FromScanAsync(ScanOperationConfig scanConfig) + public IAsyncSearch FromScanAsync(ScanOperationConfig scanConfig) { if (scanConfig == null) throw new ArgumentNullException("scanConfig"); @@ -288,7 +288,7 @@ public AsyncSearch FromScanAsync(ScanOperationConfig scanConfig) /// [Obsolete("Use the FromScanAsync overload that takes ScanConfig instead, since DynamoDBOperationConfig contains properties that are not applicable to FromScanAsync.")] - public AsyncSearch FromScanAsync(ScanOperationConfig scanConfig, DynamoDBOperationConfig operationConfig = null) + public IAsyncSearch FromScanAsync(ScanOperationConfig scanConfig, DynamoDBOperationConfig operationConfig = null) { if (scanConfig == null) throw new ArgumentNullException("scanConfig"); @@ -297,7 +297,7 @@ public AsyncSearch FromScanAsync(ScanOperationConfig scanConfig, DynamoDBO } /// - public AsyncSearch FromScanAsync(ScanOperationConfig scanConfig, FromScanConfig fromScanConfig) + public IAsyncSearch FromScanAsync(ScanOperationConfig scanConfig, FromScanConfig fromScanConfig) { if (scanConfig == null) throw new ArgumentNullException("scanConfig"); @@ -310,7 +310,7 @@ public AsyncSearch FromScanAsync(ScanOperationConfig scanConfig, FromScanC #region Query async /// - public AsyncSearch QueryAsync(object hashKeyValue) + public IAsyncSearch QueryAsync(object hashKeyValue) { var query = ConvertQueryByValue(hashKeyValue, null, null); return FromSearchAsync(query); @@ -318,21 +318,21 @@ public AsyncSearch QueryAsync(object hashKeyValue) /// [Obsolete("Use the QueryAsync overload that takes QueryConfig instead, since DynamoDBOperationConfig contains properties that are not applicable to QueryAsync.")] - public AsyncSearch QueryAsync(object hashKeyValue, DynamoDBOperationConfig operationConfig = null) + public IAsyncSearch QueryAsync(object hashKeyValue, DynamoDBOperationConfig operationConfig = null) { var query = ConvertQueryByValue(hashKeyValue, null, operationConfig); return FromSearchAsync(query); } /// - public AsyncSearch QueryAsync(object hashKeyValue, QueryConfig queryConfig) + public IAsyncSearch QueryAsync(object hashKeyValue, QueryConfig queryConfig) { var query = ConvertQueryByValue(hashKeyValue, null, queryConfig?.ToDynamoDBOperationConfig()); return FromSearchAsync(query); } /// - public AsyncSearch QueryAsync(object hashKeyValue, QueryOperator op, IEnumerable values) + public IAsyncSearch QueryAsync(object hashKeyValue, QueryOperator op, IEnumerable values) { if (values == null) throw new ArgumentNullException("values"); @@ -343,7 +343,7 @@ public AsyncSearch QueryAsync(object hashKeyValue, QueryOperator op, IEnum /// [Obsolete("Use the QueryAsync overload that takes QueryConfig instead, since DynamoDBOperationConfig contains properties that are not applicable to QueryAsync.")] - public AsyncSearch QueryAsync(object hashKeyValue, QueryOperator op, IEnumerable values, DynamoDBOperationConfig operationConfig = null) + public IAsyncSearch QueryAsync(object hashKeyValue, QueryOperator op, IEnumerable values, DynamoDBOperationConfig operationConfig = null) { if (values == null) throw new ArgumentNullException("values"); @@ -353,7 +353,7 @@ public AsyncSearch QueryAsync(object hashKeyValue, QueryOperator op, IEnum } /// - public AsyncSearch QueryAsync(object hashKeyValue, QueryOperator op, IEnumerable values, QueryConfig queryConfig) + public IAsyncSearch QueryAsync(object hashKeyValue, QueryOperator op, IEnumerable values, QueryConfig queryConfig) { if (values == null) throw new ArgumentNullException("values"); @@ -363,7 +363,7 @@ public AsyncSearch QueryAsync(object hashKeyValue, QueryOperator op, IEnum } /// - public AsyncSearch FromQueryAsync(QueryOperationConfig queryConfig) + public IAsyncSearch FromQueryAsync(QueryOperationConfig queryConfig) { if (queryConfig == null) throw new ArgumentNullException("queryConfig"); @@ -373,7 +373,7 @@ public AsyncSearch FromQueryAsync(QueryOperationConfig queryConfig) /// [Obsolete("Use the FromQueryAsync overload that takes QueryConfig instead, since DynamoDBOperationConfig contains properties that are not applicable to FromQueryAsync.")] - public AsyncSearch FromQueryAsync(QueryOperationConfig queryConfig, DynamoDBOperationConfig operationConfig = null) + public IAsyncSearch FromQueryAsync(QueryOperationConfig queryConfig, DynamoDBOperationConfig operationConfig = null) { if (queryConfig == null) throw new ArgumentNullException("queryConfig"); @@ -382,7 +382,7 @@ public AsyncSearch FromQueryAsync(QueryOperationConfig queryConfig, Dynamo } /// - public AsyncSearch FromQueryAsync(QueryOperationConfig queryConfig, FromQueryConfig fromQueryConfig) + public IAsyncSearch FromQueryAsync(QueryOperationConfig queryConfig, FromQueryConfig fromQueryConfig) { if (queryConfig == null) throw new ArgumentNullException("queryConfig"); diff --git a/sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/IDynamoDBContext.Async.cs b/sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/IDynamoDBContext.Async.cs index 1417c11689c8..b84b785ac6c4 100644 --- a/sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/IDynamoDBContext.Async.cs +++ b/sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/IDynamoDBContext.Async.cs @@ -482,7 +482,7 @@ partial interface IDynamoDBContext /// Conditions that the results should meet. /// /// AsyncSearch which can be used to retrieve DynamoDB data. - AsyncSearch ScanAsync(IEnumerable conditions); + IAsyncSearch ScanAsync(IEnumerable conditions); /// /// Configures an async Scan operation against DynamoDB, finding items @@ -496,7 +496,7 @@ partial interface IDynamoDBContext /// AsyncSearch which can be used to retrieve DynamoDB data. [Obsolete("Use the ScanAsync overload that takes ScanConfig instead, since DynamoDBOperationConfig contains properties that are not applicable to ScanAsync.")] - AsyncSearch ScanAsync(IEnumerable conditions, DynamoDBOperationConfig operationConfig = null); + IAsyncSearch ScanAsync(IEnumerable conditions, DynamoDBOperationConfig operationConfig = null); /// /// Configures an async Scan operation against DynamoDB, finding items @@ -508,7 +508,7 @@ partial interface IDynamoDBContext /// /// Config object that can be used to override properties on the table's context for this request. /// AsyncSearch which can be used to retrieve DynamoDB data. - AsyncSearch ScanAsync(IEnumerable conditions, ScanConfig scanConfig); + IAsyncSearch ScanAsync(IEnumerable conditions, ScanConfig scanConfig); /// /// Configures an async Scan operation against DynamoDB, finding items @@ -517,7 +517,7 @@ partial interface IDynamoDBContext /// Type of object. /// Scan request object. /// AsyncSearch which can be used to retrieve DynamoDB data. - AsyncSearch FromScanAsync(ScanOperationConfig scanConfig); + IAsyncSearch FromScanAsync(ScanOperationConfig scanConfig); /// /// Configures an async Scan operation against DynamoDB, finding items @@ -528,7 +528,7 @@ partial interface IDynamoDBContext /// Config object which can be used to override the table used. /// AsyncSearch which can be used to retrieve DynamoDB data. [Obsolete("Use the FromScanAsync overload that takes ScanConfig instead, since DynamoDBOperationConfig contains properties that are not applicable to FromScanAsync.")] - AsyncSearch FromScanAsync(ScanOperationConfig scanConfig, DynamoDBOperationConfig operationConfig = null); + IAsyncSearch FromScanAsync(ScanOperationConfig scanConfig, DynamoDBOperationConfig operationConfig = null); /// /// Configures an async Scan operation against DynamoDB, finding items @@ -538,7 +538,7 @@ partial interface IDynamoDBContext /// Scan request object. /// Config object that can be used to override properties on the table's context for this request. /// AsyncSearch which can be used to retrieve DynamoDB data. - AsyncSearch FromScanAsync(ScanOperationConfig scanConfig, FromScanConfig fromScanConfig); + IAsyncSearch FromScanAsync(ScanOperationConfig scanConfig, FromScanConfig fromScanConfig); #endregion @@ -551,7 +551,7 @@ partial interface IDynamoDBContext /// Type of object. /// Hash key of the items to query. /// AsyncSearch which can be used to retrieve DynamoDB data. - AsyncSearch QueryAsync(object hashKeyValue); + IAsyncSearch QueryAsync(object hashKeyValue); /// /// Configures an async Query operation against DynamoDB, finding items @@ -562,7 +562,7 @@ partial interface IDynamoDBContext /// Config object which can be used to override the table used. /// AsyncSearch which can be used to retrieve DynamoDB data. [Obsolete("Use the QueryAsync overload that takes QueryConfig instead, since DynamoDBOperationConfig contains properties that are not applicable to QueryAsync.")] - AsyncSearch QueryAsync(object hashKeyValue, DynamoDBOperationConfig operationConfig = null); + IAsyncSearch QueryAsync(object hashKeyValue, DynamoDBOperationConfig operationConfig = null); /// /// Configures an async Query operation against DynamoDB, finding items @@ -572,7 +572,7 @@ partial interface IDynamoDBContext /// Hash key of the items to query. /// Config object that can be used to override properties on the table's context for this request. /// AsyncSearch which can be used to retrieve DynamoDB data. - AsyncSearch QueryAsync(object hashKeyValue, QueryConfig queryConfig); + IAsyncSearch QueryAsync(object hashKeyValue, QueryConfig queryConfig); /// /// Configures an async Query operation against DynamoDB, finding items @@ -587,7 +587,7 @@ partial interface IDynamoDBContext /// For QueryOperator.Betwee, values should be two values. /// /// AsyncSearch which can be used to retrieve DynamoDB data. - AsyncSearch QueryAsync(object hashKeyValue, QueryOperator op, IEnumerable values); + IAsyncSearch QueryAsync(object hashKeyValue, QueryOperator op, IEnumerable values); /// /// Configures an async Query operation against DynamoDB, finding items @@ -604,7 +604,7 @@ partial interface IDynamoDBContext /// Config object which can be used to override the table used. /// AsyncSearch which can be used to retrieve DynamoDB data. [Obsolete("Use the QueryAsync overload that takes QueryConfig instead, since DynamoDBOperationConfig contains properties that are not applicable to QueryAsync.")] - AsyncSearch QueryAsync(object hashKeyValue, QueryOperator op, IEnumerable values, DynamoDBOperationConfig operationConfig = null); + IAsyncSearch QueryAsync(object hashKeyValue, QueryOperator op, IEnumerable values, DynamoDBOperationConfig operationConfig = null); /// /// Configures an async Query operation against DynamoDB, finding items @@ -620,7 +620,7 @@ partial interface IDynamoDBContext /// /// Config object that can be used to override properties on the table's context for this request. /// AsyncSearch which can be used to retrieve DynamoDB data. - AsyncSearch QueryAsync(object hashKeyValue, QueryOperator op, IEnumerable values, QueryConfig queryConfig); + IAsyncSearch QueryAsync(object hashKeyValue, QueryOperator op, IEnumerable values, QueryConfig queryConfig); /// /// Configures an async Query operation against DynamoDB using a mid-level document model @@ -629,7 +629,7 @@ partial interface IDynamoDBContext /// Type of object. /// Mid-level, document model query request object. /// AsyncSearch which can be used to retrieve DynamoDB data. - AsyncSearch FromQueryAsync(QueryOperationConfig queryConfig); + IAsyncSearch FromQueryAsync(QueryOperationConfig queryConfig); /// /// Configures an async Query operation against DynamoDB, finding items @@ -640,7 +640,7 @@ partial interface IDynamoDBContext /// Config object which can be used to override the table used. /// AsyncSearch which can be used to retrieve DynamoDB data. [Obsolete("Use the FromQueryAsync overload that takes QueryConfig instead, since DynamoDBOperationConfig contains properties that are not applicable to FromQueryAsync.")] - AsyncSearch FromQueryAsync(QueryOperationConfig queryConfig, DynamoDBOperationConfig operationConfig = null); + IAsyncSearch FromQueryAsync(QueryOperationConfig queryConfig, DynamoDBOperationConfig operationConfig = null); /// /// Configures an async Query operation against DynamoDB using a mid-level document model @@ -650,7 +650,7 @@ partial interface IDynamoDBContext /// Mid-level, document model query request object. /// Config object that can be used to override properties on the table's context for this request. /// AsyncSearch which can be used to retrieve DynamoDB data. - AsyncSearch FromQueryAsync(QueryOperationConfig queryConfig, FromQueryConfig fromQueryConfig); + IAsyncSearch FromQueryAsync(QueryOperationConfig queryConfig, FromQueryConfig fromQueryConfig); #endregion } diff --git a/sdk/test/Services/DynamoDBv2/UnitTests/Custom/MockabilityTests/AsyncSearchTests.cs b/sdk/test/Services/DynamoDBv2/UnitTests/Custom/MockabilityTests/AsyncSearchTests.cs new file mode 100644 index 000000000000..825a203e9179 --- /dev/null +++ b/sdk/test/Services/DynamoDBv2/UnitTests/Custom/MockabilityTests/AsyncSearchTests.cs @@ -0,0 +1,93 @@ +using Amazon.DynamoDBv2.DataModel; +using Amazon.DynamoDBv2.DocumentModel; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace AWSSDK.UnitTests.DynamoDBv2.NetFramework.Custom.MockabilityTests +{ + [TestClass] + public class AsyncSearchTests + { + [TestMethod] + public async Task TestMockability_ScanAsync() + { + var mockContext = new Mock(); + mockContext + .Setup(x => x.ScanAsync(It.IsAny>())) + .Returns(CreateMockAsyncSearch(new List { "item1", "item2" })); + + var ddbContext = mockContext.Object; + var asyncSearch = ddbContext.ScanAsync(null); + + var results = await asyncSearch.GetNextSetAsync(); + Assert.AreEqual(2, results.Count); + Assert.AreEqual("item1", results[0]); + Assert.AreEqual("item2", results[1]); + } + + [TestMethod] + public async Task TestMockability_FromScanAsync() + { + var mockContext = new Mock(); + mockContext + .Setup(x => x.FromScanAsync(It.IsAny())) + .Returns(CreateMockAsyncSearch(new List { "item1", "item2" })); + + var ddbContext = mockContext.Object; + var asyncSearch = ddbContext.FromScanAsync(null); + + var results = await asyncSearch.GetNextSetAsync(); + Assert.AreEqual(2, results.Count); + Assert.AreEqual("item1", results[0]); + Assert.AreEqual("item2", results[1]); + } + + [TestMethod] + public async Task TestMockability_QueryAsync() + { + var mockContext = new Mock(); + mockContext + .Setup(x => x.QueryAsync(It.IsAny())) + .Returns(CreateMockAsyncSearch(new List { "item1", "item2" })); + + var ddbContext = mockContext.Object; + var asyncSearch = ddbContext.QueryAsync(null); + + var results = await asyncSearch.GetNextSetAsync(); + Assert.AreEqual(2, results.Count); + Assert.AreEqual("item1", results[0]); + Assert.AreEqual("item2", results[1]); + } + + [TestMethod] + public async Task TestMockability_FromQueryAsync() + { + var mockContext = new Mock(); + mockContext + .Setup(x => x.FromQueryAsync(It.IsAny())) + .Returns(CreateMockAsyncSearch(new List { "item1", "item2" })); + + var ddbContext = mockContext.Object; + var asyncSearch = ddbContext.FromQueryAsync(null); + + var results = await asyncSearch.GetNextSetAsync(); + Assert.AreEqual(2, results.Count); + Assert.AreEqual("item1", results[0]); + Assert.AreEqual("item2", results[1]); + } + + public IAsyncSearch CreateMockAsyncSearch(List items) + { + var mockAsyncSearch = new Mock>(); + + mockAsyncSearch + .Setup(x => x.GetNextSetAsync(It.IsAny())) + .Returns(Task.FromResult(items)); + + return mockAsyncSearch.Object; + } + } +}