From d02c49516408536e8ab6f44f23b03cc36795d19a Mon Sep 17 00:00:00 2001 From: Johann M Date: Thu, 20 Aug 2020 07:12:54 -0500 Subject: [PATCH] Resurrect search (#195) * obsolete disk_size and data_size * ibmcom/couchdb3 docker image * search comments removed --- azure-pipelines-cd.yml | 2 +- azure-pipelines-ci.yml | 2 +- docker-compose.yml | 2 +- source/projects/MyCouch/Contexts/Searches.cs | 102 ++-- .../SearchIndexHttpRequestFactory.cs | 218 ++++----- source/projects/MyCouch/IMyCouchClient.cs | 2 +- source/projects/MyCouch/ISearchParameters.cs | 140 +++--- source/projects/MyCouch/ISearches.cs | 58 +-- source/projects/MyCouch/MyCouchClient.cs | 4 +- .../MyCouch/MyCouchClientBootstrapper.cs | 18 +- .../MyCouch/Requests/SearchIndexRequest.cs | 330 ++++++------- .../Factories/SearchIndexResponseFactory.cs | 68 +-- .../MyCouch/Responses/GetDatabaseResponse.cs | 17 +- .../projects/MyCouch/Responses/JsonScheme.cs | 3 +- .../SearchIndexResponseMaterializer.cs | 48 +- .../MyCouch/Responses/SearchIndexResponse.cs | 136 +++--- .../MyCouch/SearchParametersConfigurator.cs | 366 +++++++-------- .../MyCouch/Searching/SearchParameters.cs | 60 +-- .../IntegrationTests/CoreTests/SearchTests.cs | 444 +++++++++--------- .../IntegrationTestsRuntime.cs | 2 +- .../IntegrationTests/integrationtests.json | 1 + source/tests/Testing/Shoulds.cs | 4 +- .../SearchIndexHttpRequestFactoryTests.cs | 359 +++++++------- .../Responses/SearchIndexResponseTests.cs | 48 +- .../SearchParametersConfiguratorTests.cs | 231 ++++----- 25 files changed, 1345 insertions(+), 1320 deletions(-) diff --git a/azure-pipelines-cd.yml b/azure-pipelines-cd.yml index a9b7c3ce..467ed7be 100644 --- a/azure-pipelines-cd.yml +++ b/azure-pipelines-cd.yml @@ -16,7 +16,7 @@ pr: none resources: containers: - container: couchdb - image: couchdb:2.3.1 + image: ibmcom/couchdb3:3.1.0 ports: - 5984:5984 env: diff --git a/azure-pipelines-ci.yml b/azure-pipelines-ci.yml index 4ef6655d..cb88cafe 100644 --- a/azure-pipelines-ci.yml +++ b/azure-pipelines-ci.yml @@ -20,7 +20,7 @@ pr: resources: containers: - container: couchdb - image: couchdb:2.3.1 + image: ibmcom/couchdb3:3.1.0 ports: - 5984:5984 env: diff --git a/docker-compose.yml b/docker-compose.yml index 3301df0c..1f36230c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ version: '3' services: couchdb: - image: "couchdb:2.3.1" + image: "ibmcom/couchdb3:3.1.0" environment: COUCHDB_USER: ${MyCouch_User} COUCHDB_PASSWORD: ${MyCouch_Pass} diff --git a/source/projects/MyCouch/Contexts/Searches.cs b/source/projects/MyCouch/Contexts/Searches.cs index 60e31b9e..9edbeaef 100644 --- a/source/projects/MyCouch/Contexts/Searches.cs +++ b/source/projects/MyCouch/Contexts/Searches.cs @@ -1,51 +1,51 @@ -//using System.Threading.Tasks; -//using EnsureThat; -//using MyCouch.Extensions; -//using MyCouch.HttpRequestFactories; -//using MyCouch.Requests; -//using MyCouch.Responses; -//using MyCouch.Responses.Factories; -//using MyCouch.Serialization; - -//namespace MyCouch.Contexts -//{ -// public class Searches : ApiContextBase, ISearches -// { -// protected SearchIndexHttpRequestFactory SearchIndexHttpRequestFactory { get; set; } -// protected SearchIndexResponseFactory SearchIndexResponseFactory { get; set; } - -// public Searches(IDbConnection connection, ISerializer documentSerializer, ISerializer serializer) -// : base(connection) -// { -// Ensure.That(documentSerializer, "documentSerializer").IsNotNull(); -// Ensure.Any.IsNotNull(serializer, nameof(serializer)); - -// SearchIndexHttpRequestFactory = new SearchIndexHttpRequestFactory(serializer); -// SearchIndexResponseFactory = new SearchIndexResponseFactory(documentSerializer); -// } - -// public virtual async Task SearchAsync(SearchIndexRequest request) -// { -// Ensure.Any.IsNotNull(request, nameof(request)); - -// var httpRequest = SearchIndexHttpRequestFactory.Create(request); - -// using (var res = await SendAsync(httpRequest).ForAwait()) -// { -// return await SearchIndexResponseFactory.CreateAsync(res).ForAwait(); -// } -// } - -// public virtual async Task> SearchAsync(SearchIndexRequest request) -// { -// Ensure.Any.IsNotNull(request, nameof(request)); - -// var httpRequest = SearchIndexHttpRequestFactory.Create(request); - -// using (var res = await SendAsync(httpRequest).ForAwait()) -// { -// return await SearchIndexResponseFactory.CreateAsync(res).ForAwait(); -// } -// } -// } -//} \ No newline at end of file +using System.Threading.Tasks; +using EnsureThat; +using MyCouch.Extensions; +using MyCouch.HttpRequestFactories; +using MyCouch.Requests; +using MyCouch.Responses; +using MyCouch.Responses.Factories; +using MyCouch.Serialization; + +namespace MyCouch.Contexts +{ + public class Searches : ApiContextBase, ISearches + { + protected SearchIndexHttpRequestFactory SearchIndexHttpRequestFactory { get; set; } + protected SearchIndexResponseFactory SearchIndexResponseFactory { get; set; } + + public Searches(IDbConnection connection, ISerializer documentSerializer, ISerializer serializer) + : base(connection) + { + Ensure.That(documentSerializer, "documentSerializer").IsNotNull(); + Ensure.Any.IsNotNull(serializer, nameof(serializer)); + + SearchIndexHttpRequestFactory = new SearchIndexHttpRequestFactory(serializer); + SearchIndexResponseFactory = new SearchIndexResponseFactory(documentSerializer); + } + + public virtual async Task SearchAsync(SearchIndexRequest request) + { + Ensure.Any.IsNotNull(request, nameof(request)); + + var httpRequest = SearchIndexHttpRequestFactory.Create(request); + + using (var res = await SendAsync(httpRequest).ForAwait()) + { + return await SearchIndexResponseFactory.CreateAsync(res).ForAwait(); + } + } + + public virtual async Task> SearchAsync(SearchIndexRequest request) + { + Ensure.Any.IsNotNull(request, nameof(request)); + + var httpRequest = SearchIndexHttpRequestFactory.Create(request); + + using (var res = await SendAsync(httpRequest).ForAwait()) + { + return await SearchIndexResponseFactory.CreateAsync(res).ForAwait(); + } + } + } +} \ No newline at end of file diff --git a/source/projects/MyCouch/HttpRequestFactories/SearchIndexHttpRequestFactory.cs b/source/projects/MyCouch/HttpRequestFactories/SearchIndexHttpRequestFactory.cs index 2b3746ef..2ded8e42 100644 --- a/source/projects/MyCouch/HttpRequestFactories/SearchIndexHttpRequestFactory.cs +++ b/source/projects/MyCouch/HttpRequestFactories/SearchIndexHttpRequestFactory.cs @@ -1,110 +1,110 @@ -//using System.Collections.Generic; -//using System.Linq; -//using System.Net.Http; -//using EnsureThat; -//using MyCouch.Net; -//using MyCouch.Requests; -//using MyCouch.Serialization; - -//namespace MyCouch.HttpRequestFactories -//{ -// public class SearchIndexHttpRequestFactory -// { -// protected ISerializer Serializer { get; private set; } - -// public SearchIndexHttpRequestFactory(ISerializer serializer) -// { -// Ensure.Any.IsNotNull(serializer, nameof(serializer)); - -// Serializer = serializer; -// } - -// public virtual HttpRequest Create(SearchIndexRequest request) -// { -// Ensure.Any.IsNotNull(request, nameof(request)); - -// return new HttpRequest(HttpMethod.Get, GenerateRelativeUrl(request)) -// .SetRequestTypeHeader(request.GetType()); -// } - -// protected virtual string GenerateRelativeUrl(SearchIndexRequest request) -// { -// return string.Format("/_design/{0}/_search/{1}{2}", -// new UrlSegment(request.IndexIdentity.DesignDocument), -// new UrlSegment(request.IndexIdentity.Name), -// GenerateRequestUrlQueryString(request)); -// } - -// protected virtual string GenerateRequestUrlQueryString(SearchIndexRequest request) -// { -// var p = GenerateQueryStringParams(request); - -// return string.IsNullOrEmpty(p) ? string.Empty : string.Concat("?", p); -// } - -// protected virtual string GenerateQueryStringParams(SearchIndexRequest request) -// { -// return string.Join("&", GenerateJsonCompatibleKeyValues(request) -// .Select(kv => string.Format("{0}={1}", kv.Key, UrlParam.Encode(kv.Value)))); -// } - -// protected virtual IDictionary GenerateJsonCompatibleKeyValues(SearchIndexRequest request) -// { -// var kvs = new Dictionary(); - -// if (!string.IsNullOrWhiteSpace(request.Expression)) -// kvs.Add(KeyNames.Expression, request.Expression); - -// if (request.HasSortings()) -// kvs.Add(KeyNames.Sort, Serializer.ToJsonArray(request.Sort.ToArray())); - -// if (!string.IsNullOrWhiteSpace(request.Bookmark)) -// kvs.Add(KeyNames.Bookmark, request.Bookmark); - -// if (request.Stale.HasValue) -// kvs.Add(KeyNames.Stale, request.Stale.Value.AsString()); - -// if (request.Limit.HasValue) -// kvs.Add(KeyNames.Limit, Serializer.ToJson(request.Limit.Value)); - -// if (request.IncludeDocs.HasValue) -// kvs.Add(KeyNames.IncludeDocs, Serializer.ToJson(request.IncludeDocs.Value)); +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using EnsureThat; +using MyCouch.Net; +using MyCouch.Requests; +using MyCouch.Serialization; + +namespace MyCouch.HttpRequestFactories +{ + public class SearchIndexHttpRequestFactory + { + protected ISerializer Serializer { get; private set; } + + public SearchIndexHttpRequestFactory(ISerializer serializer) + { + Ensure.Any.IsNotNull(serializer, nameof(serializer)); + + Serializer = serializer; + } + + public virtual HttpRequest Create(SearchIndexRequest request) + { + Ensure.Any.IsNotNull(request, nameof(request)); + + return new HttpRequest(HttpMethod.Get, GenerateRelativeUrl(request)) + .SetRequestTypeHeader(request.GetType()); + } + + protected virtual string GenerateRelativeUrl(SearchIndexRequest request) + { + return string.Format("/_design/{0}/_search/{1}{2}", + new UrlSegment(request.IndexIdentity.DesignDocument), + new UrlSegment(request.IndexIdentity.Name), + GenerateRequestUrlQueryString(request)); + } + + protected virtual string GenerateRequestUrlQueryString(SearchIndexRequest request) + { + var p = GenerateQueryStringParams(request); + + return string.IsNullOrEmpty(p) ? string.Empty : string.Concat("?", p); + } + + protected virtual string GenerateQueryStringParams(SearchIndexRequest request) + { + return string.Join("&", GenerateJsonCompatibleKeyValues(request) + .Select(kv => string.Format("{0}={1}", kv.Key, UrlParam.Encode(kv.Value)))); + } + + protected virtual IDictionary GenerateJsonCompatibleKeyValues(SearchIndexRequest request) + { + var kvs = new Dictionary(); + + if (!string.IsNullOrWhiteSpace(request.Expression)) + kvs.Add(KeyNames.Expression, request.Expression); + + if (request.HasSortings()) + kvs.Add(KeyNames.Sort, Serializer.ToJsonArray(request.Sort.ToArray())); + + if (!string.IsNullOrWhiteSpace(request.Bookmark)) + kvs.Add(KeyNames.Bookmark, request.Bookmark); + + if (request.Stale.HasValue) + kvs.Add(KeyNames.Stale, request.Stale.Value.AsString()); + + if (request.Limit.HasValue) + kvs.Add(KeyNames.Limit, Serializer.ToJson(request.Limit.Value)); + + if (request.IncludeDocs.HasValue) + kvs.Add(KeyNames.IncludeDocs, Serializer.ToJson(request.IncludeDocs.Value)); -// if (request.Ranges != null) -// kvs.Add(KeyNames.Ranges, Serializer.Serialize(request.Ranges)); - -// if (request.HasCounts()) -// kvs.Add(KeyNames.Counts, Serializer.ToJsonArray(request.Counts.ToArray())); - -// if (!string.IsNullOrWhiteSpace(request.GroupField)) -// kvs.Add(KeyNames.GroupField, request.GroupField); - -// if (request.GroupLimit.HasValue) -// kvs.Add(KeyNames.GroupLimit, Serializer.ToJson(request.GroupLimit.Value)); - -// if (request.HasGroupSortings()) -// kvs.Add(KeyNames.GroupSort, Serializer.ToJsonArray(request.GroupSort.ToArray())); - -// if (request.DrillDown.HasValue) -// kvs.Add(KeyNames.DrillDown, Serializer.ToJsonArray(new[] { request.DrillDown.Value.Key, request.DrillDown.Value.Value })); - -// return kvs; -// } - -// protected static class KeyNames -// { -// public const string Expression = "q"; -// public const string Sort = "sort"; -// public const string Bookmark = "bookmark"; -// public const string Stale = "stale"; -// public const string Limit = "limit"; -// public const string IncludeDocs = "include_docs"; -// public const string Ranges = "ranges"; -// public const string Counts = "counts"; -// public const string GroupField = "group_field"; -// public const string GroupLimit = "group_limit"; -// public const string GroupSort = "group_sort"; -// public const string DrillDown = "drilldown"; -// } -// } -//} \ No newline at end of file + if (request.Ranges != null) + kvs.Add(KeyNames.Ranges, Serializer.Serialize(request.Ranges)); + + if (request.HasCounts()) + kvs.Add(KeyNames.Counts, Serializer.ToJsonArray(request.Counts.ToArray())); + + if (!string.IsNullOrWhiteSpace(request.GroupField)) + kvs.Add(KeyNames.GroupField, request.GroupField); + + if (request.GroupLimit.HasValue) + kvs.Add(KeyNames.GroupLimit, Serializer.ToJson(request.GroupLimit.Value)); + + if (request.HasGroupSortings()) + kvs.Add(KeyNames.GroupSort, Serializer.ToJsonArray(request.GroupSort.ToArray())); + + if (request.DrillDown.HasValue) + kvs.Add(KeyNames.DrillDown, Serializer.ToJsonArray(new[] { request.DrillDown.Value.Key, request.DrillDown.Value.Value })); + + return kvs; + } + + protected static class KeyNames + { + public const string Expression = "q"; + public const string Sort = "sort"; + public const string Bookmark = "bookmark"; + public const string Stale = "stale"; + public const string Limit = "limit"; + public const string IncludeDocs = "include_docs"; + public const string Ranges = "ranges"; + public const string Counts = "counts"; + public const string GroupField = "group_field"; + public const string GroupLimit = "group_limit"; + public const string GroupSort = "group_sort"; + public const string DrillDown = "drilldown"; + } + } +} \ No newline at end of file diff --git a/source/projects/MyCouch/IMyCouchClient.cs b/source/projects/MyCouch/IMyCouchClient.cs index 2b9dfa6e..567dd332 100644 --- a/source/projects/MyCouch/IMyCouchClient.cs +++ b/source/projects/MyCouch/IMyCouchClient.cs @@ -65,7 +65,7 @@ public interface IMyCouchClient : IDisposable ///// ///// Used to access Search Indexes. ///// - //ISearches Searches { get; } + ISearches Searches { get; } /// /// View oriented API operations, for accessing and managing views. diff --git a/source/projects/MyCouch/ISearchParameters.cs b/source/projects/MyCouch/ISearchParameters.cs index 9623fdfb..e03386ee 100644 --- a/source/projects/MyCouch/ISearchParameters.cs +++ b/source/projects/MyCouch/ISearchParameters.cs @@ -1,83 +1,83 @@ -//using System.Collections.Generic; +using System.Collections.Generic; -//namespace MyCouch -//{ -// /// -// /// The different common search parameters that can be specified -// /// when performing a query against a Search-index. -// /// -// public interface ISearchParameters -// { -// /// -// /// Identitfies the Search index that this request will be -// /// performed against. -// /// -// SearchIndexIdentity IndexIdentity { get; } +namespace MyCouch +{ + /// + /// The different common search parameters that can be specified + /// when performing a query against a Search-index. + /// + public interface ISearchParameters + { + /// + /// Identitfies the Search index that this request will be + /// performed against. + /// + SearchIndexIdentity IndexIdentity { get; } -// /// -// /// The Lucene expression that will be used to query the index. -// /// -// string Expression { get; set; } + /// + /// The Lucene expression that will be used to query the index. + /// + string Expression { get; set; } -// /// -// /// Allow the results from a stale search index to be used. -// /// -// Stale? Stale { get; set; } + /// + /// Allow the results from a stale search index to be used. + /// + Stale? Stale { get; set; } -// /// -// /// A bookmark that was received from a previous search. This -// /// allows you to page through the results. If there are no more -// /// results after the bookmark, you will get a response with an -// /// empty rows array and the same bookmark. That way you can -// /// determine that you have reached the end of the result list. -// /// -// string Bookmark { get; set; } + /// + /// A bookmark that was received from a previous search. This + /// allows you to page through the results. If there are no more + /// results after the bookmark, you will get a response with an + /// empty rows array and the same bookmark. That way you can + /// determine that you have reached the end of the result list. + /// + string Bookmark { get; set; } -// /// -// /// Sort expressions used to sort the output. -// /// -// IList Sort { get; set; } + /// + /// Sort expressions used to sort the output. + /// + IList Sort { get; set; } -// /// -// /// Include the full content of the documents in the return. -// /// -// bool? IncludeDocs { get; set; } + /// + /// Include the full content of the documents in the return. + /// + bool? IncludeDocs { get; set; } -// /// -// /// Limit the number of the returned documents to the specified number. -// /// -// int? Limit { get; set; } + /// + /// Limit the number of the returned documents to the specified number. + /// + int? Limit { get; set; } -// /// -// /// Defines ranges for faceted numeric search fields. -// /// -// object Ranges { get; set; } + /// + /// Defines ranges for faceted numeric search fields. + /// + object Ranges { get; set; } -// /// -// /// List of field names for which counts should be produced. -// /// -// IList Counts { get; set; } + /// + /// List of field names for which counts should be produced. + /// + IList Counts { get; set; } -// /// -// /// Field by which to group search matches. -// /// -// string GroupField { get; set; } + /// + /// Field by which to group search matches. + /// + string GroupField { get; set; } -// /// -// /// Maximum group count. This field can only be used if group_field is specified. -// /// -// int? GroupLimit { get; set; } + /// + /// Maximum group count. This field can only be used if group_field is specified. + /// + int? GroupLimit { get; set; } -// /// -// /// This field defines the order of the groups in a search using group_field. -// /// The default sort order is relevance. -// /// -// IList GroupSort { get; set; } + /// + /// This field defines the order of the groups in a search using group_field. + /// The default sort order is relevance. + /// + IList GroupSort { get; set; } -// /// -// /// Defines a pair of field name and value so that search only matches -// /// documents that that have the given value in the field name. -// /// -// KeyValuePair? DrillDown { get; set; } -// } -//} \ No newline at end of file + /// + /// Defines a pair of field name and value so that search only matches + /// documents that that have the given value in the field name. + /// + KeyValuePair? DrillDown { get; set; } + } +} \ No newline at end of file diff --git a/source/projects/MyCouch/ISearches.cs b/source/projects/MyCouch/ISearches.cs index e39b8e08..36575ed8 100644 --- a/source/projects/MyCouch/ISearches.cs +++ b/source/projects/MyCouch/ISearches.cs @@ -1,31 +1,31 @@ -//using System.Threading.Tasks; -//using MyCouch.Requests; -//using MyCouch.Responses; +using System.Threading.Tasks; +using MyCouch.Requests; +using MyCouch.Responses; -//namespace MyCouch -//{ -// /// -// /// Used to access Search Indexes. -// /// -// public interface ISearches -// { -// /// -// /// Lets you perform a search using Lucene powered -// /// Search API by using a reusable . -// /// Any returned IncludedDoc will be treated as JSON. -// /// -// /// -// /// -// Task SearchAsync(SearchIndexRequest request); +namespace MyCouch +{ + /// + /// Used to access Search Indexes. + /// + public interface ISearches + { + /// + /// Lets you perform a search using Lucene powered + /// Search API by using a reusable . + /// Any returned IncludedDoc will be treated as JSON. + /// + /// + /// + Task SearchAsync(SearchIndexRequest request); -// /// -// /// Lets you perform a search using Lucene powered -// /// Search API by using a reusable . -// /// Any returned IncludedDoc will be treated as . -// /// -// /// -// /// -// /// -// Task> SearchAsync(SearchIndexRequest request); -// } -//} \ No newline at end of file + /// + /// Lets you perform a search using Lucene powered + /// Search API by using a reusable . + /// Any returned IncludedDoc will be treated as . + /// + /// + /// + /// + Task> SearchAsync(SearchIndexRequest request); + } +} \ No newline at end of file diff --git a/source/projects/MyCouch/MyCouchClient.cs b/source/projects/MyCouch/MyCouchClient.cs index 1da349f8..92d0607b 100644 --- a/source/projects/MyCouch/MyCouchClient.cs +++ b/source/projects/MyCouch/MyCouchClient.cs @@ -17,7 +17,7 @@ public class MyCouchClient : IMyCouchClient public IDocuments Documents { get; } public IEntities Entities { get; } public IQueries Queries { get; } - //public ISearches Searches { get; } + public ISearches Searches { get; } public IViews Views { get; } public MyCouchClient(string serverAddress, string dbName, MyCouchClientBootstrapper bootstrapper = null) @@ -42,7 +42,7 @@ public MyCouchClient(DbConnectionInfo connectionInfo, MyCouchClientBootstrapper Documents = bootstrapper.DocumentsFn(Connection); Entities = bootstrapper.EntitiesFn(Connection); Queries = bootstrapper.QueriesFn(Connection); - //Searches = bootstrapper.SearchesFn(Connection); + Searches = bootstrapper.SearchesFn(Connection); Views = bootstrapper.ViewsFn(Connection); } diff --git a/source/projects/MyCouch/MyCouchClientBootstrapper.cs b/source/projects/MyCouch/MyCouchClientBootstrapper.cs index ded28958..09a03ed2 100644 --- a/source/projects/MyCouch/MyCouchClientBootstrapper.cs +++ b/source/projects/MyCouch/MyCouchClientBootstrapper.cs @@ -95,7 +95,7 @@ public class MyCouchClientBootstrapper ///// ///// Used e.g. for bootrstraping . ///// - //public Func SearchesFn { get; set; } + public Func SearchesFn { get; set; } /// /// Used e.g. for bootstraping . @@ -120,7 +120,7 @@ public MyCouchClientBootstrapper() ConfigureDocumentsFn(); ConfigureEntitiesFn(); ConfigureQueriesFn(); - //ConfigureSearchesFn(); + ConfigureSearchesFn(); ConfigureViewsFn(); } @@ -182,13 +182,13 @@ protected virtual void ConfigureQueriesFn() SerializerFn()); } - //protected virtual void ConfigureSearchesFn() - //{ - // SearchesFn = cn => new Searches( - // cn, - // DocumentSerializerFn(), - // SerializerFn()); - //} + protected virtual void ConfigureSearchesFn() + { + SearchesFn = cn => new Searches( + cn, + DocumentSerializerFn(), + SerializerFn()); + } protected virtual void ConfigureViewsFn() { diff --git a/source/projects/MyCouch/Requests/SearchIndexRequest.cs b/source/projects/MyCouch/Requests/SearchIndexRequest.cs index a0f843d7..099a7623 100644 --- a/source/projects/MyCouch/Requests/SearchIndexRequest.cs +++ b/source/projects/MyCouch/Requests/SearchIndexRequest.cs @@ -1,165 +1,165 @@ -//using System; -//using System.Collections.Generic; -//using System.Linq; -//using EnsureThat; -//using MyCouch.Searching; - -//namespace MyCouch.Requests -//{ -// public class SearchIndexRequest : Request, ISearchParameters -// { -// protected ISearchParameters State { get; private set; } - -// /// -// /// Identitfies the Search index that this request will be -// /// performed against. -// /// -// public SearchIndexIdentity IndexIdentity { get { return State.IndexIdentity; } } - -// /// -// /// The Lucene expression that will be used to query the index. -// /// -// public string Expression -// { -// get { return State.Expression; } -// set { State.Expression = value; } -// } - -// /// -// /// Allow the results from a stale search index to be used. -// /// -// public Stale? Stale -// { -// get { return State.Stale; } -// set { State.Stale = value; } -// } - -// /// -// /// A bookmark that was received from a previous search. This -// /// allows you to page through the results. If there are no more -// /// results after the bookmark, you will get a response with an -// /// empty rows array and the same bookmark. That way you can -// /// determine that you have reached the end of the result list. -// /// -// public string Bookmark -// { -// get { return State.Bookmark; } -// set { State.Bookmark = value; } -// } - -// /// -// /// Sort expressions used to sort the output. -// /// -// public IList Sort -// { -// get { return State.Sort; } -// set { State.Sort = value; } -// } - -// /// -// /// Include the full content of the documents in the return. -// /// -// public bool? IncludeDocs -// { -// get { return State.IncludeDocs; } -// set { State.IncludeDocs = value; } -// } - -// /// -// /// Limit the number of the returned documents to the specified number. -// /// -// public int? Limit -// { -// get { return State.Limit; } -// set { State.Limit = value; } -// } - -// /// -// /// Defines ranges for faceted numeric search fields. -// /// -// public object Ranges -// { -// get { return State.Ranges; } -// set { State.Ranges = value; } -// } - -// /// -// /// List of field names for which counts should be produced. -// /// -// public IList Counts -// { -// get { return State.Counts; } -// set { State.Counts = value; } -// } - -// /// -// /// Field by which to group search matches. -// /// -// public string GroupField -// { -// get { return State.GroupField; } -// set { State.GroupField = value; } -// } - -// /// -// /// Maximum group count. This field can only be used if group_field is specified. -// /// -// public int? GroupLimit -// { -// get { return State.GroupLimit; } -// set { State.GroupLimit = value; } -// } - -// /// -// /// Sort expressions that defines the order of the groups in a search using group_field. -// /// The default sort order is relevance. -// /// -// public IList GroupSort -// { -// get { return State.GroupSort; } -// set { State.GroupSort = value; } -// } - -// /// -// /// Defines a pair of field name and value so that search only matches -// /// documents that that have the given value in the field name. -// /// -// public KeyValuePair? DrillDown -// { -// get { return State.DrillDown; } -// set { State.DrillDown = value; } -// } - -// public SearchIndexRequest(string designDocument, string searchIndexName) -// : this(new SearchIndexIdentity(designDocument, searchIndexName)) { } - -// public SearchIndexRequest(SearchIndexIdentity indexIdentity) -// { -// Ensure.That(indexIdentity, "indexIdentity").IsNotNull(); - -// State = new SearchParameters(indexIdentity); -// } - -// public virtual SearchIndexRequest Configure(Action configurator) -// { -// configurator(new SearchParametersConfigurator(State)); - -// return this; -// } - -// public virtual bool HasSortings() -// { -// return Sort != null && Sort.Any(); -// } - -// public virtual bool HasCounts() -// { -// return Counts != null && Counts.Any(); -// } - -// public virtual bool HasGroupSortings() -// { -// return GroupSort != null && GroupSort.Any(); -// } -// } -//} \ No newline at end of file +using System; +using System.Collections.Generic; +using System.Linq; +using EnsureThat; +using MyCouch.Searching; + +namespace MyCouch.Requests +{ + public class SearchIndexRequest : Request, ISearchParameters + { + protected ISearchParameters State { get; private set; } + + /// + /// Identitfies the Search index that this request will be + /// performed against. + /// + public SearchIndexIdentity IndexIdentity { get { return State.IndexIdentity; } } + + /// + /// The Lucene expression that will be used to query the index. + /// + public string Expression + { + get { return State.Expression; } + set { State.Expression = value; } + } + + /// + /// Allow the results from a stale search index to be used. + /// + public Stale? Stale + { + get { return State.Stale; } + set { State.Stale = value; } + } + + /// + /// A bookmark that was received from a previous search. This + /// allows you to page through the results. If there are no more + /// results after the bookmark, you will get a response with an + /// empty rows array and the same bookmark. That way you can + /// determine that you have reached the end of the result list. + /// + public string Bookmark + { + get { return State.Bookmark; } + set { State.Bookmark = value; } + } + + /// + /// Sort expressions used to sort the output. + /// + public IList Sort + { + get { return State.Sort; } + set { State.Sort = value; } + } + + /// + /// Include the full content of the documents in the return. + /// + public bool? IncludeDocs + { + get { return State.IncludeDocs; } + set { State.IncludeDocs = value; } + } + + /// + /// Limit the number of the returned documents to the specified number. + /// + public int? Limit + { + get { return State.Limit; } + set { State.Limit = value; } + } + + /// + /// Defines ranges for faceted numeric search fields. + /// + public object Ranges + { + get { return State.Ranges; } + set { State.Ranges = value; } + } + + /// + /// List of field names for which counts should be produced. + /// + public IList Counts + { + get { return State.Counts; } + set { State.Counts = value; } + } + + /// + /// Field by which to group search matches. + /// + public string GroupField + { + get { return State.GroupField; } + set { State.GroupField = value; } + } + + /// + /// Maximum group count. This field can only be used if group_field is specified. + /// + public int? GroupLimit + { + get { return State.GroupLimit; } + set { State.GroupLimit = value; } + } + + /// + /// Sort expressions that defines the order of the groups in a search using group_field. + /// The default sort order is relevance. + /// + public IList GroupSort + { + get { return State.GroupSort; } + set { State.GroupSort = value; } + } + + /// + /// Defines a pair of field name and value so that search only matches + /// documents that that have the given value in the field name. + /// + public KeyValuePair? DrillDown + { + get { return State.DrillDown; } + set { State.DrillDown = value; } + } + + public SearchIndexRequest(string designDocument, string searchIndexName) + : this(new SearchIndexIdentity(designDocument, searchIndexName)) { } + + public SearchIndexRequest(SearchIndexIdentity indexIdentity) + { + Ensure.That(indexIdentity, "indexIdentity").IsNotNull(); + + State = new SearchParameters(indexIdentity); + } + + public virtual SearchIndexRequest Configure(Action configurator) + { + configurator(new SearchParametersConfigurator(State)); + + return this; + } + + public virtual bool HasSortings() + { + return Sort != null && Sort.Any(); + } + + public virtual bool HasCounts() + { + return Counts != null && Counts.Any(); + } + + public virtual bool HasGroupSortings() + { + return GroupSort != null && GroupSort.Any(); + } + } +} \ No newline at end of file diff --git a/source/projects/MyCouch/Responses/Factories/SearchIndexResponseFactory.cs b/source/projects/MyCouch/Responses/Factories/SearchIndexResponseFactory.cs index 6f0d3ae4..d73ac64b 100644 --- a/source/projects/MyCouch/Responses/Factories/SearchIndexResponseFactory.cs +++ b/source/projects/MyCouch/Responses/Factories/SearchIndexResponseFactory.cs @@ -1,39 +1,39 @@ -//using System.Net.Http; -//using System.Threading.Tasks; -//using EnsureThat; -//using MyCouch.Extensions; -//using MyCouch.Responses.Materializers; -//using MyCouch.Serialization; +using System.Net.Http; +using System.Threading.Tasks; +using EnsureThat; +using MyCouch.Extensions; +using MyCouch.Responses.Materializers; +using MyCouch.Serialization; -//namespace MyCouch.Responses.Factories -//{ -// public class SearchIndexResponseFactory : ResponseFactoryBase -// { -// protected readonly SearchIndexResponseMaterializer SuccessfulResponseMaterializer; -// protected readonly FailedResponseMaterializer FailedResponseMaterializer; +namespace MyCouch.Responses.Factories +{ + public class SearchIndexResponseFactory : ResponseFactoryBase + { + protected readonly SearchIndexResponseMaterializer SuccessfulResponseMaterializer; + protected readonly FailedResponseMaterializer FailedResponseMaterializer; -// public SearchIndexResponseFactory(ISerializer serializer) -// { -// Ensure.Any.IsNotNull(serializer, nameof(serializer)); + public SearchIndexResponseFactory(ISerializer serializer) + { + Ensure.Any.IsNotNull(serializer, nameof(serializer)); -// SuccessfulResponseMaterializer = new SearchIndexResponseMaterializer(serializer); -// FailedResponseMaterializer = new FailedResponseMaterializer(serializer); -// } + SuccessfulResponseMaterializer = new SearchIndexResponseMaterializer(serializer); + FailedResponseMaterializer = new FailedResponseMaterializer(serializer); + } -// public virtual async Task CreateAsync(HttpResponseMessage httpResponse) -// { -// return await MaterializeAsync( -// httpResponse, -// SuccessfulResponseMaterializer.MaterializeAsync, -// FailedResponseMaterializer.MaterializeAsync).ForAwait(); -// } + public virtual async Task CreateAsync(HttpResponseMessage httpResponse) + { + return await MaterializeAsync( + httpResponse, + SuccessfulResponseMaterializer.MaterializeAsync, + FailedResponseMaterializer.MaterializeAsync).ForAwait(); + } -// public virtual async Task> CreateAsync(HttpResponseMessage httpResponse) -// { -// return await MaterializeAsync>( -// httpResponse, -// SuccessfulResponseMaterializer.MaterializeAsync, -// FailedResponseMaterializer.MaterializeAsync); -// } -// } -//} \ No newline at end of file + public virtual async Task> CreateAsync(HttpResponseMessage httpResponse) + { + return await MaterializeAsync>( + httpResponse, + SuccessfulResponseMaterializer.MaterializeAsync, + FailedResponseMaterializer.MaterializeAsync); + } + } +} \ No newline at end of file diff --git a/source/projects/MyCouch/Responses/GetDatabaseResponse.cs b/source/projects/MyCouch/Responses/GetDatabaseResponse.cs index dd76a083..ba65f087 100644 --- a/source/projects/MyCouch/Responses/GetDatabaseResponse.cs +++ b/source/projects/MyCouch/Responses/GetDatabaseResponse.cs @@ -1,4 +1,5 @@ -using Newtonsoft.Json; +using System; +using Newtonsoft.Json; namespace MyCouch.Responses { @@ -22,13 +23,23 @@ public class GetDatabaseResponse : Response [JsonProperty(JsonScheme.CompactRunning)] public bool CompactRunning { get; set; } - [JsonProperty(JsonScheme.DiskSize)] + [JsonProperty(JsonScheme.Sizes)] + public DbSizes Sizes { get; set; } + + [Obsolete("Use sizes.file instead")] public long DiskSize { get; set; } - [JsonProperty(JsonScheme.DataSize)] + [Obsolete("Use sizes.active instead")] public long DataSize { get; set; } [JsonProperty(JsonScheme.DiskFormatVersion)] public int DiskFormatVersion { get; set; } + + public class DbSizes + { + public long File { get; set; } + public long External { get; set; } + public long Active { get; set; } + } } } \ No newline at end of file diff --git a/source/projects/MyCouch/Responses/JsonScheme.cs b/source/projects/MyCouch/Responses/JsonScheme.cs index c661e6ce..e5fb010b 100644 --- a/source/projects/MyCouch/Responses/JsonScheme.cs +++ b/source/projects/MyCouch/Responses/JsonScheme.cs @@ -42,8 +42,7 @@ public static class JsonScheme public const string DocDelCount = "doc_del_count"; public const string PurgeSeq = "purge_seq"; public const string CompactRunning = "compact_running"; - public const string DiskSize = "disk_size"; - public const string DataSize = "data_size"; + public const string Sizes = "sizes"; public const string DiskFormatVersion = "disk_format_version"; public const string DesignDoc = "ddoc"; diff --git a/source/projects/MyCouch/Responses/Materializers/SearchIndexResponseMaterializer.cs b/source/projects/MyCouch/Responses/Materializers/SearchIndexResponseMaterializer.cs index 04f7fa3e..cce08c95 100644 --- a/source/projects/MyCouch/Responses/Materializers/SearchIndexResponseMaterializer.cs +++ b/source/projects/MyCouch/Responses/Materializers/SearchIndexResponseMaterializer.cs @@ -1,28 +1,28 @@ -//using System.Net.Http; -//using System.Threading.Tasks; -//using EnsureThat; -//using MyCouch.Extensions; -//using MyCouch.Serialization; +using System.Net.Http; +using System.Threading.Tasks; +using EnsureThat; +using MyCouch.Extensions; +using MyCouch.Serialization; -//namespace MyCouch.Responses.Materializers -//{ -// public class SearchIndexResponseMaterializer -// { -// protected readonly ISerializer Serializer; +namespace MyCouch.Responses.Materializers +{ + public class SearchIndexResponseMaterializer + { + protected readonly ISerializer Serializer; -// public SearchIndexResponseMaterializer(ISerializer serializer) -// { -// Ensure.Any.IsNotNull(serializer, nameof(serializer)); + public SearchIndexResponseMaterializer(ISerializer serializer) + { + Ensure.Any.IsNotNull(serializer, nameof(serializer)); -// Serializer = serializer; -// } + Serializer = serializer; + } -// public virtual async Task MaterializeAsync(SearchIndexResponse response, HttpResponseMessage httpResponse) -// { -// using (var content = await httpResponse.Content.ReadAsStreamAsync().ForAwait()) -// { -// Serializer.Populate(response, content); -// } -// } -// } -//} \ No newline at end of file + public virtual async Task MaterializeAsync(SearchIndexResponse response, HttpResponseMessage httpResponse) + { + using (var content = await httpResponse.Content.ReadAsStreamAsync().ForAwait()) + { + Serializer.Populate(response, content); + } + } + } +} \ No newline at end of file diff --git a/source/projects/MyCouch/Responses/SearchIndexResponse.cs b/source/projects/MyCouch/Responses/SearchIndexResponse.cs index f24013b0..b2226d6c 100644 --- a/source/projects/MyCouch/Responses/SearchIndexResponse.cs +++ b/source/projects/MyCouch/Responses/SearchIndexResponse.cs @@ -1,76 +1,76 @@ -//using System; -//using System.Collections.Generic; -//using System.Linq; -//using MyCouch.Serialization.Converters; -//using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using MyCouch.Serialization.Converters; +using Newtonsoft.Json; -//namespace MyCouch.Responses -//{ -// public class SearchIndexResponse : SearchIndexResponse { } +namespace MyCouch.Responses +{ + public class SearchIndexResponse : SearchIndexResponse { } -// public class SearchIndexResponse : Response -// { -// public Row[] Rows { get; set; } -// public Group[] Groups { get; set; } -// [JsonProperty(JsonScheme.TotalRows)] -// public long TotalRows { get; set; } -// public long RowCount { get { return IsEmpty ? 0 : Rows.LongCount(); } } -// public long GroupCount { get { return IsGroupsEmpty ? 0 : Groups.LongCount(); } } -// public bool IsEmpty -// { -// get { return Rows == null || Rows.Length == 0; } -// } -// public bool IsGroupsEmpty -// { -// get { return Groups == null || Groups.Length == 0; } -// } -// public string Bookmark { get; set; } + public class SearchIndexResponse : Response + { + public Row[] Rows { get; set; } + public Group[] Groups { get; set; } + [JsonProperty(JsonScheme.TotalRows)] + public long TotalRows { get; set; } + public long RowCount { get { return IsEmpty ? 0 : Rows.LongCount(); } } + public long GroupCount { get { return IsGroupsEmpty ? 0 : Groups.LongCount(); } } + public bool IsEmpty + { + get { return Rows == null || Rows.Length == 0; } + } + public bool IsGroupsEmpty + { + get { return Groups == null || Groups.Length == 0; } + } + public string Bookmark { get; set; } -// [JsonConverter(typeof(MultiTypeDeserializationJsonConverter))] -// public string Counts { get; set; } + [JsonConverter(typeof(MultiTypeDeserializationJsonConverter))] + public string Counts { get; set; } -// [JsonConverter(typeof(MultiTypeDeserializationJsonConverter))] -// public string Ranges { get; set; } + [JsonConverter(typeof(MultiTypeDeserializationJsonConverter))] + public string Ranges { get; set; } -// public override string ToStringDebugVersion() -// { -// return string.Format("{0}{1}{0}IsEmpty: {2}{0}TotalRows: {3}{0}RowCount: {4}{0}Bookmark: {5}{0}GroupCount: {6}", -// Environment.NewLine, -// base.ToStringDebugVersion(), -// IsEmpty, -// TotalRows, -// RowCount, -// Bookmark, -// GroupCount); -// } -// public class Row -// { -// public string Id { get; set; } -// public object[] Order { get; set; } -// public Dictionary Fields { get; set; } + public override string ToStringDebugVersion() + { + return string.Format("{0}{1}{0}IsEmpty: {2}{0}TotalRows: {3}{0}RowCount: {4}{0}Bookmark: {5}{0}GroupCount: {6}", + Environment.NewLine, + base.ToStringDebugVersion(), + IsEmpty, + TotalRows, + RowCount, + Bookmark, + GroupCount); + } + public class Row + { + public string Id { get; set; } + public object[] Order { get; set; } + public Dictionary Fields { get; set; } -// [JsonProperty(JsonScheme.IncludedDoc)] -// [JsonConverter(typeof(MultiTypeDeserializationJsonConverter))] -// public TIncludedDoc IncludedDoc { get; set; } + [JsonProperty(JsonScheme.IncludedDoc)] + [JsonConverter(typeof(MultiTypeDeserializationJsonConverter))] + public TIncludedDoc IncludedDoc { get; set; } -// public virtual double[] GetOrderAsDoubles() -// { -// return Order == null || Order.Length == 0 -// ? new double[0] : Order.Cast().ToArray(); -// } -// } + public virtual double[] GetOrderAsDoubles() + { + return Order == null || Order.Length == 0 + ? new double[0] : Order.Cast().ToArray(); + } + } -// public class Group -// { -// public string By { get; set; } -// [JsonProperty(JsonScheme.TotalRows)] -// public long TotalRows { get; set; } -// public Row[] Rows { get; set; } -// public bool IsEmpty -// { -// get { return Rows == null || Rows.Length == 0; } -// } -// public long RowCount { get { return IsEmpty ? 0 : Rows.Length; } } -// } -// } -//} \ No newline at end of file + public class Group + { + public string By { get; set; } + [JsonProperty(JsonScheme.TotalRows)] + public long TotalRows { get; set; } + public Row[] Rows { get; set; } + public bool IsEmpty + { + get { return Rows == null || Rows.Length == 0; } + } + public long RowCount { get { return IsEmpty ? 0 : Rows.Length; } } + } + } +} \ No newline at end of file diff --git a/source/projects/MyCouch/SearchParametersConfigurator.cs b/source/projects/MyCouch/SearchParametersConfigurator.cs index 6da4bbb6..02959e56 100644 --- a/source/projects/MyCouch/SearchParametersConfigurator.cs +++ b/source/projects/MyCouch/SearchParametersConfigurator.cs @@ -1,183 +1,183 @@ -//using System.Linq; -//using EnsureThat; -//using System.Collections.Generic; - -//namespace MyCouch -//{ -// public class SearchParametersConfigurator -// { -// protected readonly ISearchParameters Parameters; - -// public SearchParametersConfigurator(ISearchParameters parameters) -// { -// Parameters = parameters; -// } - -// /// -// /// Lucene expression that will be used to query the index. -// /// -// /// -// /// -// public virtual SearchParametersConfigurator Expression(string value) -// { -// Ensure.String.IsNotNullOrWhiteSpace(value, nameof(value)); - -// Parameters.Expression = value; - -// return this; -// } - -// /// -// /// Allow the results from a stale search index to be used. -// /// -// /// -// /// -// public virtual SearchParametersConfigurator Stale(Stale value) -// { -// Parameters.Stale = value; - -// return this; -// } - -// /// -// /// A bookmark that was received from a previous search. This -// /// allows you to page through the results. If there are no more -// /// results after the bookmark, you will get a response with an -// /// empty rows array and the same bookmark. That way you can -// /// determine that you have reached the end of the result list. -// /// -// /// -// /// -// public virtual SearchParametersConfigurator Bookmark(string value) -// { -// Ensure.String.IsNotNullOrWhiteSpace(value, nameof(value)); - -// Parameters.Bookmark = value; - -// return this; -// } - -// /// -// /// Sort expressions used to sort the output. -// /// -// /// -// /// -// public virtual SearchParametersConfigurator Sort(params string[] sortExpressions) -// { -// Ensure.That(sortExpressions, "sortExpressions").HasItems(); - -// Parameters.Sort = sortExpressions.ToList(); - -// return this; -// } - -// /// -// /// Include the full content of the documents in the return; -// /// -// /// -// /// -// public virtual SearchParametersConfigurator IncludeDocs(bool value) -// { -// Parameters.IncludeDocs = value; - -// return this; -// } - -// /// -// /// Limit the number of the returned documents to the specified number. -// /// -// /// -// /// -// public virtual SearchParametersConfigurator Limit(int value) -// { -// Parameters.Limit = value; - -// return this; -// } - -// /// -// /// Expression to define ranges for faceted numeric search fields -// /// -// /// -// /// -// public virtual SearchParametersConfigurator Ranges(object ranges) -// { -// Ensure.That(ranges, "ranges").IsNotNull(); - -// Parameters.Ranges = ranges; - -// return this; -// } - - - -// /// -// /// List of field names for which counts should be produced. -// /// -// /// -// /// -// public virtual SearchParametersConfigurator Counts(params string[] counts) -// { -// Ensure.That(counts, "value").HasItems(); - -// Parameters.Counts = counts.ToList(); - -// return this; -// } - -// /// -// /// Field by which to group search matches. -// /// -// /// -// /// -// public virtual SearchParametersConfigurator GroupField(string value) -// { -// Ensure.String.IsNotNullOrWhiteSpace(value, nameof(value)); - -// Parameters.GroupField = value; - -// return this; -// } - -// /// -// /// Maximum group count. This field can only be used if group_field is specified. -// /// -// /// -// /// -// public virtual SearchParametersConfigurator GroupLimit(int value) -// { -// Parameters.GroupLimit = value; - -// return this; -// } - -// /// -// /// This field defines the order of the groups in a search using group_field. -// /// The default sort order is relevance. -// /// -// /// -// /// -// public virtual SearchParametersConfigurator GroupSort(params string[] sortExpressions) -// { -// Ensure.That(sortExpressions, "sortExpressions").HasItems(); - -// Parameters.GroupSort = sortExpressions.ToList(); - -// return this; -// } - -// /// -// /// Defines a pair of field name and value so that search only matches -// /// documents that that have the given value in the field name. -// /// -// public virtual SearchParametersConfigurator DrillDown(string name, string value) -// { -// EnsureArg.IsNotNullOrWhiteSpace(name, nameof(name)); -// Ensure.String.IsNotNullOrWhiteSpace(value, nameof(value)); - -// Parameters.DrillDown = new KeyValuePair(name, value); - -// return this; -// } -// } -//} \ No newline at end of file +using System.Linq; +using EnsureThat; +using System.Collections.Generic; + +namespace MyCouch +{ + public class SearchParametersConfigurator + { + protected readonly ISearchParameters Parameters; + + public SearchParametersConfigurator(ISearchParameters parameters) + { + Parameters = parameters; + } + + /// + /// Lucene expression that will be used to query the index. + /// + /// + /// + public virtual SearchParametersConfigurator Expression(string value) + { + Ensure.String.IsNotNullOrWhiteSpace(value, nameof(value)); + + Parameters.Expression = value; + + return this; + } + + /// + /// Allow the results from a stale search index to be used. + /// + /// + /// + public virtual SearchParametersConfigurator Stale(Stale value) + { + Parameters.Stale = value; + + return this; + } + + /// + /// A bookmark that was received from a previous search. This + /// allows you to page through the results. If there are no more + /// results after the bookmark, you will get a response with an + /// empty rows array and the same bookmark. That way you can + /// determine that you have reached the end of the result list. + /// + /// + /// + public virtual SearchParametersConfigurator Bookmark(string value) + { + Ensure.String.IsNotNullOrWhiteSpace(value, nameof(value)); + + Parameters.Bookmark = value; + + return this; + } + + /// + /// Sort expressions used to sort the output. + /// + /// + /// + public virtual SearchParametersConfigurator Sort(params string[] sortExpressions) + { + Ensure.That(sortExpressions, "sortExpressions").HasItems(); + + Parameters.Sort = sortExpressions.ToList(); + + return this; + } + + /// + /// Include the full content of the documents in the return; + /// + /// + /// + public virtual SearchParametersConfigurator IncludeDocs(bool value) + { + Parameters.IncludeDocs = value; + + return this; + } + + /// + /// Limit the number of the returned documents to the specified number. + /// + /// + /// + public virtual SearchParametersConfigurator Limit(int value) + { + Parameters.Limit = value; + + return this; + } + + /// + /// Expression to define ranges for faceted numeric search fields + /// + /// + /// + public virtual SearchParametersConfigurator Ranges(object ranges) + { + Ensure.That(ranges, "ranges").IsNotNull(); + + Parameters.Ranges = ranges; + + return this; + } + + + + /// + /// List of field names for which counts should be produced. + /// + /// + /// + public virtual SearchParametersConfigurator Counts(params string[] counts) + { + Ensure.That(counts, "value").HasItems(); + + Parameters.Counts = counts.ToList(); + + return this; + } + + /// + /// Field by which to group search matches. + /// + /// + /// + public virtual SearchParametersConfigurator GroupField(string value) + { + Ensure.String.IsNotNullOrWhiteSpace(value, nameof(value)); + + Parameters.GroupField = value; + + return this; + } + + /// + /// Maximum group count. This field can only be used if group_field is specified. + /// + /// + /// + public virtual SearchParametersConfigurator GroupLimit(int value) + { + Parameters.GroupLimit = value; + + return this; + } + + /// + /// This field defines the order of the groups in a search using group_field. + /// The default sort order is relevance. + /// + /// + /// + public virtual SearchParametersConfigurator GroupSort(params string[] sortExpressions) + { + Ensure.That(sortExpressions, "sortExpressions").HasItems(); + + Parameters.GroupSort = sortExpressions.ToList(); + + return this; + } + + /// + /// Defines a pair of field name and value so that search only matches + /// documents that that have the given value in the field name. + /// + public virtual SearchParametersConfigurator DrillDown(string name, string value) + { + EnsureArg.IsNotNullOrWhiteSpace(name, nameof(name)); + Ensure.String.IsNotNullOrWhiteSpace(value, nameof(value)); + + Parameters.DrillDown = new KeyValuePair(name, value); + + return this; + } + } +} \ No newline at end of file diff --git a/source/projects/MyCouch/Searching/SearchParameters.cs b/source/projects/MyCouch/Searching/SearchParameters.cs index 3e3b3307..a5cd4389 100644 --- a/source/projects/MyCouch/Searching/SearchParameters.cs +++ b/source/projects/MyCouch/Searching/SearchParameters.cs @@ -1,33 +1,33 @@ -//using System; -//using System.Collections.Generic; -//using EnsureThat; +using System; +using System.Collections.Generic; +using EnsureThat; -//namespace MyCouch.Searching -//{ -// public class SearchParameters : ISearchParameters -// { -// public SearchIndexIdentity IndexIdentity { get; private set; } -// public string Expression { get; set; } -// public Stale? Stale { get; set; } -// public string Bookmark { get; set; } -// public IList Sort { get; set; } -// public bool? IncludeDocs { get; set; } -// public int? Limit { get; set; } -// public object Ranges { get; set; } -// public IList Counts { get; set; } -// public string GroupField { get; set; } -// public int? GroupLimit { get; set; } -// public IList GroupSort { get; set; } -// public KeyValuePair? DrillDown { get; set; } +namespace MyCouch.Searching +{ + public class SearchParameters : ISearchParameters + { + public SearchIndexIdentity IndexIdentity { get; private set; } + public string Expression { get; set; } + public Stale? Stale { get; set; } + public string Bookmark { get; set; } + public IList Sort { get; set; } + public bool? IncludeDocs { get; set; } + public int? Limit { get; set; } + public object Ranges { get; set; } + public IList Counts { get; set; } + public string GroupField { get; set; } + public int? GroupLimit { get; set; } + public IList GroupSort { get; set; } + public KeyValuePair? DrillDown { get; set; } -// public SearchParameters(SearchIndexIdentity searchIndexIdentity) -// { -// Ensure.That(searchIndexIdentity, "searchIndexIdentity").IsNotNull(); + public SearchParameters(SearchIndexIdentity searchIndexIdentity) + { + Ensure.That(searchIndexIdentity, "searchIndexIdentity").IsNotNull(); -// IndexIdentity = searchIndexIdentity; -// Sort = new List(); -// Counts = new List(); -// GroupSort = new List(); -// } -// } -//} \ No newline at end of file + IndexIdentity = searchIndexIdentity; + Sort = new List(); + Counts = new List(); + GroupSort = new List(); + } + } +} \ No newline at end of file diff --git a/source/tests/IntegrationTests/CoreTests/SearchTests.cs b/source/tests/IntegrationTests/CoreTests/SearchTests.cs index dbe2d79b..7ebc59a6 100644 --- a/source/tests/IntegrationTests/CoreTests/SearchTests.cs +++ b/source/tests/IntegrationTests/CoreTests/SearchTests.cs @@ -1,216 +1,228 @@ -//using System.Linq; -//using FluentAssertions; -//using MyCouch.IntegrationTests.TestFixtures; -//using MyCouch.Requests; -//using MyCouch.Testing; -//using MyCouch.Testing.Model; -//using MyCouch.Testing.TestData; -//using Xunit; - -//namespace IntegrationTests.CoreTests -//{ -// public class SearchTests : IntegrationTestsOf, -// IPreserveStatePerFixture, -// IClassFixture -// { -// protected Animal[] Animals { get; set; } - -// public SearchTests(SearchFixture data) -// { -// Animals = data.Init(Environment); -// SUT = DbClient.Searches; -// } - -// [MyFact(TestScenarios.SearchesContext)] -// public void Can_search_on_default_index_using_simple_expression() -// { -// var searchRequest = new SearchIndexRequest(CloudantTestData.Views.Views101AnimalsSearchIndexId).Configure(q => q -// .Expression("kookaburra")); - -// var response = SUT.SearchAsync(searchRequest).Result; - -// response.Should().BeSuccessfulGet(numOfRows: 1); -// response.Bookmark.Should().NotBeNullOrEmpty(); -// response.Rows[0].Id.Should().Be("kookaburra"); -// response.Rows[0].Order[0].Should().Be(1.4054651260375977); -// response.Rows[0].Order[1].Should().Be((long)0); -// response.Rows[0].Fields.Count.Should().Be(5); -// response.Rows[0].Fields["diet"].Should().Be("carnivore"); -// response.Rows[0].Fields["minLength"].Should().Be(0.28); -// response.Rows[0].Fields["class"].Should().Be("bird"); -// response.Rows[0].Fields["latinName"].Should().Be("Dacelo novaeguineae"); -// response.Rows[0].IncludedDoc.Should().BeNull(); -// } - -// [MyFact(TestScenarios.SearchesContext)] -// public void Can_search_on_more_complex_expressions() -// { -// var searchRequest = new SearchIndexRequest(CloudantTestData.Views.Views101AnimalsSearchIndexId).Configure(q => q -// .Expression("diet:carnivore AND minLength:[1 TO 3]")); - -// var response = SUT.SearchAsync(searchRequest).Result; - -// response.Should().BeSuccessfulGet(numOfRows: 1); -// response.Bookmark.Should().NotBeNullOrEmpty(); -// response.Rows[0].Id.Should().Be("panda"); -// response.Rows[0].Order[0].Should().Be(1.4142135381698608); -// response.Rows[0].Order[1].Should().Be((long)1); -// response.Rows[0].Fields.Count.Should().Be(4); -// response.Rows[0].Fields["diet"].Should().Be("carnivore"); -// response.Rows[0].Fields["minLength"].Should().Be(1.2); -// response.Rows[0].Fields["class"].Should().Be("mammal"); -// response.Rows[0].IncludedDoc.Should().BeNull(); -// } - -// [MyFact(TestScenarios.SearchesContext)] -// public void Can_sort() -// { -// var searchRequest = new SearchIndexRequest(CloudantTestData.Views.Views101AnimalsSearchIndexId).Configure(q => q -// .Expression("diet:carnivore") -// .Sort("-minLength")); - -// var response = SUT.SearchAsync(searchRequest).Result; - -// response.Should().BeSuccessfulGet(numOfRows: 2); -// response.Bookmark.Should().NotBeNullOrEmpty(); -// response.Rows[0].Id.Should().Be("panda"); -// response.Rows[0].Order[0].Should().Be(1.2); -// response.Rows[0].Order[1].Should().Be((long)1); -// response.Rows[0].Fields["diet"].Should().Be("carnivore"); -// response.Rows[0].Fields["minLength"].Should().Be(1.2); - -// response.Rows[1].Id.Should().Be("kookaburra"); -// response.Rows[1].Order[0].Should().Be(0.28); -// response.Rows[1].Order[1].Should().Be((long)0); -// response.Rows[1].Fields["diet"].Should().Be("carnivore"); -// response.Rows[1].Fields["minLength"].Should().Be(0.28); -// } - -// [MyFact(TestScenarios.SearchesContext)] -// public void Can_include_docs() -// { -// var searchRequest = new SearchIndexRequest(CloudantTestData.Views.Views101AnimalsSearchIndexId).Configure(q => q -// .Expression("kookaburra") -// .IncludeDocs(true)); - -// var response = SUT.SearchAsync(searchRequest).Result; - -// response.Should().BeSuccessfulGet(numOfRows: 1); - -// var doc = DbClient.Documents.GetAsync(response.Rows[0].Id).Result; -// response.Rows[0].IncludedDoc.Should().Be(doc.Content); -// } - -// [MyFact(TestScenarios.SearchesContext)] -// public void Can_include_docs_to_specific_entity() -// { -// var searchRequest = new SearchIndexRequest(CloudantTestData.Views.Views101AnimalsSearchIndexId).Configure(q => q -// .Expression("kookaburra") -// .IncludeDocs(true)); - -// var response = SUT.SearchAsync(searchRequest).Result; - -// response.Should().BeSuccessfulGet(numOfRows: 1); - -// var orgDoc = Animals.Single(a => a.AnimalId == response.Rows[0].Id); -// var returnedDoc = response.Rows[0].IncludedDoc; - -// returnedDoc.Should().BeEquivalentTo(orgDoc); -// } - -// [MyFact(TestScenarios.SearchesContext)] -// public void Can_limit() -// { -// var searchRequest = new SearchIndexRequest(CloudantTestData.Views.Views101AnimalsSearchIndexId).Configure(q => q -// .Expression("class:mammal") -// .Limit(1)); - -// var response = SUT.SearchAsync(searchRequest).Result; - -// response.Should().BeSuccessfulGet(numOfRows: 1); -// response.TotalRows.Should().Be(8); -// } - -// [MyFact(TestScenarios.SearchesContext)] -// public void Can_navigate_using_bookmarks() -// { -// var searchRequest = new SearchIndexRequest(CloudantTestData.Views.Views101AnimalsSearchIndexId).Configure(q => q -// .Expression("class:mammal") -// .Limit(1)); - -// var response1 = SUT.SearchAsync(searchRequest).Result; - -// response1.Should().BeSuccessfulGet(numOfRows: 1); -// response1.TotalRows.Should().Be(8); -// response1.Rows[0].Id.Should().Be("panda"); - -// searchRequest.Configure(q => q -// .Bookmark(response1.Bookmark)); - -// var response2 = SUT.SearchAsync(searchRequest).Result; -// response2.Should().BeSuccessfulGet(numOfRows: 1); -// response2.TotalRows.Should().Be(8); -// response2.Rows[0].Id.Should().Be("aardvark"); -// } - -// [MyFact(TestScenarios.SearchesContext)] -// public void Can_report_counts_by_multiple_fields() -// { -// var searchRequest = new SearchIndexRequest(CloudantTestData.Views.Views101AnimalsSearchIndexId).Configure(q => q -// .Expression("minLength:[1 TO 3]") -// .Counts("diet", "class")); - -// var response = SUT.SearchAsync(searchRequest).Result; - -// response.Should().BeSuccessfulGet(numOfRows: 4); -// response.Counts.Should().NotBeNullOrWhiteSpace(); -// var counts = DbClient.Serializer.Deserialize(response.Counts); -// ((double)counts.@class.mammal).Should().Be(4.0); -// ((double)counts.diet.carnivore).Should().Be(1.0); -// ((double)counts.diet.herbivore).Should().Be(2.0); -// ((double)counts.diet.omnivore).Should().Be(1.0); -// } - -// [MyFact(TestScenarios.SearchesContext)] -// public void Can_report_ranges_by_multiple_fields() -// { -// var searchRequest = new SearchIndexRequest(CloudantTestData.Views.Views101AnimalsSearchIndexId).Configure(q => q -// .Expression("minLength:[1 TO 3]") -// .Ranges( -// new -// { -// minLength = new { minLow = "[0 TO 100]", minHigh = "{101 TO Infinity}" }, -// maxLength = new { maxLow = "[0 TO 100]", maxHigh = "{101 TO Infinity}" } -// } -// )); - -// var response = SUT.SearchAsync(searchRequest).Result; - -// response.Should().BeSuccessfulGet(numOfRows: 4); -// response.Ranges.Should().NotBeNullOrWhiteSpace(); -// var ranges = DbClient.Serializer.Deserialize(response.Ranges); -// ((double)ranges.minLength.minLow).Should().Be(4.0); -// ((double)ranges.minLength.minHigh).Should().Be(0.0); -// ((double)ranges.maxLength.maxLow).Should().Be(4.0); -// ((double)ranges.maxLength.maxHigh).Should().Be(0.0); -// } - -// [MyFact(TestScenarios.SearchesContext)] -// public void Can_drilldown_searches_by_field_value() -// { -// var searchRequest = new SearchIndexRequest(CloudantTestData.Views.Views101AnimalsSearchIndexId).Configure(q => q -// .Expression("class:(bird OR mammal)") -// .Counts("diet") -// .DrillDown("class", "bird")); - -// var response = SUT.SearchAsync(searchRequest).Result; - -// response.Should().BeSuccessfulGet(numOfRows: 2); -// response.Rows.Should().NotContain(r => (string)r.Fields["class"] != "bird"); -// response.Counts.Should().NotBeNullOrWhiteSpace(); -// var counts = DbClient.Serializer.Deserialize(response.Counts); -// ((double)counts.diet.carnivore).Should().Be(1.0); -// ((double)counts.diet.omnivore).Should().Be(1.0); -// } -// } -//} \ No newline at end of file +using System.Linq; +using FluentAssertions; +using IntegrationTests.TestFixtures; +using MyCouch; +using MyCouch.Requests; +using MyCouch.Testing; +using MyCouch.Testing.Model; +using MyCouch.Testing.TestData; +using Xunit; + +namespace IntegrationTests.CoreTests +{ + public class SearchTests : IntegrationTestsOf, + IPreserveStatePerFixture, + IClassFixture + { + protected Animal[] Animals { get; set; } + + public SearchTests(SearchFixture data) + { + Animals = data.Init(Environment); + SUT = DbClient.Searches; + } + + [MyFact(TestScenarios.SearchesContext)] + public void Can_search_on_default_index_using_simple_expression() + { + var searchRequest = new SearchIndexRequest(CloudantTestData.Views.Views101AnimalsSearchIndexId).Configure(q => q + .Expression("kookaburra")); + + var response = SUT.SearchAsync(searchRequest).Result; + + response.IsSuccess.Should().Be(true); + response.RowCount.Should().Be(1); + response.Bookmark.Should().NotBeNullOrEmpty(); + response.Rows[0].Id.Should().Be("kookaburra"); + response.Rows[0].Order[0].Should().Be(2.098612070083618); + response.Rows[0].Order[1].Should().Be((long)2); + response.Rows[0].Fields.Count.Should().Be(5); + response.Rows[0].Fields["diet"].Should().Be("carnivore"); + response.Rows[0].Fields["minLength"].Should().Be(0.28); + response.Rows[0].Fields["class"].Should().Be("bird"); + response.Rows[0].Fields["latinName"].Should().Be("Dacelo novaeguineae"); + response.Rows[0].IncludedDoc.Should().BeNull(); + } + + [MyFact(TestScenarios.SearchesContext)] + public void Can_search_on_more_complex_expressions() + { + var searchRequest = new SearchIndexRequest(CloudantTestData.Views.Views101AnimalsSearchIndexId).Configure(q => q + .Expression("diet:carnivore AND minLength:[1 TO 3]")); + + var response = SUT.SearchAsync(searchRequest).Result; + + response.IsSuccess.Should().Be(true); + response.RowCount.Should().Be(1); + response.Bookmark.Should().NotBeNullOrEmpty(); + response.Rows[0].Id.Should().Be("panda"); + response.Rows[0].Order[0].Should().Be(1.9664045572280884); + response.Rows[0].Order[1].Should().Be((long)3); + response.Rows[0].Fields.Count.Should().Be(4); + response.Rows[0].Fields["diet"].Should().Be("carnivore"); + response.Rows[0].Fields["minLength"].Should().Be(1.2); + response.Rows[0].Fields["class"].Should().Be("mammal"); + response.Rows[0].IncludedDoc.Should().BeNull(); + } + + [MyFact(TestScenarios.SearchesContext)] + public void Can_sort() + { + var searchRequest = new SearchIndexRequest(CloudantTestData.Views.Views101AnimalsSearchIndexId).Configure(q => q + .Expression("diet:carnivore") + .Sort("-minLength")); + + var response = SUT.SearchAsync(searchRequest).Result; + + response.IsSuccess.Should().Be(true); + response.RowCount.Should().Be(2); + response.Bookmark.Should().NotBeNullOrEmpty(); + response.Rows[0].Id.Should().Be("panda"); + response.Rows[0].Order[0].Should().Be(1.2); + response.Rows[0].Order[1].Should().Be((long)3); + response.Rows[0].Fields["diet"].Should().Be("carnivore"); + response.Rows[0].Fields["minLength"].Should().Be(1.2); + + response.Rows[1].Id.Should().Be("kookaburra"); + response.Rows[1].Order[0].Should().Be(0.28); + response.Rows[1].Order[1].Should().Be((long)2); + response.Rows[1].Fields["diet"].Should().Be("carnivore"); + response.Rows[1].Fields["minLength"].Should().Be(0.28); + } + + [MyFact(TestScenarios.SearchesContext)] + public void Can_include_docs() + { + var searchRequest = new SearchIndexRequest(CloudantTestData.Views.Views101AnimalsSearchIndexId).Configure(q => q + .Expression("kookaburra") + .IncludeDocs(true)); + + var response = SUT.SearchAsync(searchRequest).Result; + + response.IsSuccess.Should().Be(true); + response.RowCount.Should().Be(1); + + var doc = DbClient.Documents.GetAsync(response.Rows[0].Id).Result; + response.Rows[0].IncludedDoc.Should().Be(doc.Content); + } + + [MyFact(TestScenarios.SearchesContext)] + public void Can_include_docs_to_specific_entity() + { + var searchRequest = new SearchIndexRequest(CloudantTestData.Views.Views101AnimalsSearchIndexId).Configure(q => q + .Expression("kookaburra") + .IncludeDocs(true)); + + var response = SUT.SearchAsync(searchRequest).Result; + + response.IsSuccess.Should().Be(true); + response.RowCount.Should().Be(1); + + var orgDoc = Animals.Single(a => a.AnimalId == response.Rows[0].Id); + var returnedDoc = response.Rows[0].IncludedDoc; + + returnedDoc.Should().BeEquivalentTo(orgDoc); + } + + [MyFact(TestScenarios.SearchesContext)] + public void Can_limit() + { + var searchRequest = new SearchIndexRequest(CloudantTestData.Views.Views101AnimalsSearchIndexId).Configure(q => q + .Expression("class:mammal") + .Limit(1)); + + var response = SUT.SearchAsync(searchRequest).Result; + + response.IsSuccess.Should().Be(true); + response.RowCount.Should().Be(1); + response.TotalRows.Should().Be(8); + } + + [MyFact(TestScenarios.SearchesContext)] + public void Can_navigate_using_bookmarks() + { + var searchRequest = new SearchIndexRequest(CloudantTestData.Views.Views101AnimalsSearchIndexId).Configure(q => q + .Expression("class:mammal") + .Limit(1)); + + var response1 = SUT.SearchAsync(searchRequest).Result; + + response1.IsSuccess.Should().Be(true); + response1.RowCount.Should().Be(1); + response1.TotalRows.Should().Be(8); + response1.Rows[0].Id.Should().Be("aardvark"); + + searchRequest.Configure(q => q + .Bookmark(response1.Bookmark)); + + var response2 = SUT.SearchAsync(searchRequest).Result; + response2.IsSuccess.Should().Be(true); + response2.RowCount.Should().Be(1); + response2.TotalRows.Should().Be(8); + response2.Rows[0].Id.Should().Be("giraffe"); + } + + [MyFact(TestScenarios.SearchesContext)] + public void Can_report_counts_by_multiple_fields() + { + var searchRequest = new SearchIndexRequest(CloudantTestData.Views.Views101AnimalsSearchIndexId).Configure(q => q + .Expression("minLength:[1 TO 3]") + .Counts("diet", "class")); + + var response = SUT.SearchAsync(searchRequest).Result; + + response.IsSuccess.Should().Be(true); + response.RowCount.Should().Be(4); + response.Counts.Should().NotBeNullOrWhiteSpace(); + var counts = DbClient.Serializer.Deserialize(response.Counts); + ((double)counts.@class.mammal).Should().Be(4.0); + ((double)counts.diet.carnivore).Should().Be(1.0); + ((double)counts.diet.herbivore).Should().Be(2.0); + ((double)counts.diet.omnivore).Should().Be(1.0); + } + + [MyFact(TestScenarios.SearchesContext)] + public void Can_report_ranges_by_multiple_fields() + { + var searchRequest = new SearchIndexRequest(CloudantTestData.Views.Views101AnimalsSearchIndexId).Configure(q => q + .Expression("minLength:[1 TO 3]") + .Ranges( + new + { + minLength = new { minLow = "[0 TO 100]", minHigh = "{101 TO Infinity}" }, + maxLength = new { maxLow = "[0 TO 100]", maxHigh = "{101 TO Infinity}" } + } + )); + + var response = SUT.SearchAsync(searchRequest).Result; + + response.IsSuccess.Should().Be(true); + response.RowCount.Should().Be(4); + response.Ranges.Should().NotBeNullOrWhiteSpace(); + var ranges = DbClient.Serializer.Deserialize(response.Ranges); + ((double)ranges.minLength.minLow).Should().Be(4.0); + ((double)ranges.minLength.minHigh).Should().Be(0.0); + ((double)ranges.maxLength.maxLow).Should().Be(4.0); + ((double)ranges.maxLength.maxHigh).Should().Be(0.0); + } + + [MyFact(TestScenarios.SearchesContext)] + public void Can_drilldown_searches_by_field_value() + { + var searchRequest = new SearchIndexRequest(CloudantTestData.Views.Views101AnimalsSearchIndexId).Configure(q => q + .Expression("class:(bird OR mammal)") + .Counts("diet") + .DrillDown("class", "bird")); + + var response = SUT.SearchAsync(searchRequest).Result; + + response.IsSuccess.Should().Be(true); + response.RowCount.Should().Be(2); + response.Rows.Should().NotContain(r => (string)r.Fields["class"] != "bird"); + response.Counts.Should().NotBeNullOrWhiteSpace(); + var counts = DbClient.Serializer.Deserialize(response.Counts); + ((double)counts.diet.carnivore).Should().Be(1.0); + ((double)counts.diet.omnivore).Should().Be(1.0); + } + } +} \ No newline at end of file diff --git a/source/tests/IntegrationTests/IntegrationTestsRuntime.cs b/source/tests/IntegrationTests/IntegrationTestsRuntime.cs index c5c534b9..6a399821 100644 --- a/source/tests/IntegrationTests/IntegrationTestsRuntime.cs +++ b/source/tests/IntegrationTests/IntegrationTestsRuntime.cs @@ -221,7 +221,7 @@ public static class TestScenarios public const string DocumentsContext = "documentscontext"; public const string EntitiesContext = "entitiescontext"; public const string ViewsContext = "viewscontext"; - //public const string SearchesContext = "searchescontext"; + public const string SearchesContext = "searchescontext"; public const string QueriesContext = "queriescontext"; public const string ListsContext = "listscontext"; public const string ShowsContext = "showscontext"; diff --git a/source/tests/IntegrationTests/integrationtests.json b/source/tests/IntegrationTests/integrationtests.json index 2e4ef5ae..d45a6f74 100644 --- a/source/tests/IntegrationTests/integrationtests.json +++ b/source/tests/IntegrationTests/integrationtests.json @@ -7,6 +7,7 @@ "changescontext", "documentscontext", "entitiescontext", + "searchescontext", "queriescontext", "viewscontext", "listscontext", diff --git a/source/tests/Testing/Shoulds.cs b/source/tests/Testing/Shoulds.cs index e9eb0f8e..b52a0781 100644 --- a/source/tests/Testing/Shoulds.cs +++ b/source/tests/Testing/Shoulds.cs @@ -134,8 +134,8 @@ public void BeSuccessful(string dbName) Response.DbName.Should().NotBeNullOrEmpty(); Response.DbName.Should().Be(dbName); Response.UpdateSeq.Should().NotBeNullOrEmpty(); - Response.DataSize.Should().BeGreaterThan(0); - Response.DiskSize.Should().BeGreaterThan(0); + Response.Sizes.Active.Should().BeGreaterThan(0); + Response.Sizes.File.Should().BeGreaterThan(0); Response.DocCount.Should().BeGreaterThan(0); Response.DocDelCount.Should().BeGreaterThan(0); Response.DiskFormatVersion.Should().BeGreaterThan(0); diff --git a/source/tests/UnitTests/HttpRequestFactories/SearchIndexHttpRequestFactoryTests.cs b/source/tests/UnitTests/HttpRequestFactories/SearchIndexHttpRequestFactoryTests.cs index b53912f6..5c383902 100644 --- a/source/tests/UnitTests/HttpRequestFactories/SearchIndexHttpRequestFactoryTests.cs +++ b/source/tests/UnitTests/HttpRequestFactories/SearchIndexHttpRequestFactoryTests.cs @@ -1,179 +1,180 @@ -//using System; -//using FluentAssertions; -//using MyCouch.HttpRequestFactories; -//using MyCouch.Net; -//using MyCouch.Requests; -//using MyCouch.Testing; -//using Xunit; - -//namespace UnitTests.HttpRequestFactories -//{ -// public class SearchIndexHttpRequestFactoryTests : UnitTestsOf -// { -// public SearchIndexHttpRequestFactoryTests() -// { -// var boostrapper = new MyCouchClientBootstrapper(); -// SUT = new SearchIndexHttpRequestFactory(boostrapper.SerializerFn()); -// } - -// [Fact] -// public void When_not_configured_It_yields_no_content_nor_querystring() -// { -// var request = CreateRequest(); - -// WithHttpRequestFor( -// request, -// req => -// { -// req.Content.Should().BeNull(); -// req.RelativeUrl.ToUnescapedQuery().Should().Be(string.Empty); -// }); -// } - -// [Fact] -// public void When_Expression_is_assigned_It_should_get_included_in_the_querystring() -// { -// var request = CreateRequest(); -// request.Expression = "Some value"; - -// WithHttpRequestFor( -// request, -// req => req.RelativeUrl.ToUnescapedQuery().Should().Be("?q=Some value")); -// } - -// [Fact] -// public void When_Bookmark_is_assigned_It_should_get_included_in_the_querystring() -// { -// var request = CreateRequest(); -// request.Bookmark = "g1AAAADOeJzLYWBgYM5gTmGQT0lKzi9KdUhJMtbLSs1LLUst0kvOyS9NScwr0ctLLckBKmRKZEiy____f1YGk5v9l1kRDUCxRCaideexAEmGBiAFNGM_2JBvNSdBYomMJBpyAGLIfxRDmLIAxz9DAg"; - -// WithHttpRequestFor( -// request, -// req => req.RelativeUrl.ToUnescapedQuery().Should().Be("?bookmark=g1AAAADOeJzLYWBgYM5gTmGQT0lKzi9KdUhJMtbLSs1LLUst0kvOyS9NScwr0ctLLckBKmRKZEiy____f1YGk5v9l1kRDUCxRCaideexAEmGBiAFNGM_2JBvNSdBYomMJBpyAGLIfxRDmLIAxz9DAg")); -// } - -// [Fact] -// public void When_IncludeDocs_is_assigned_true_It_should_get_included_in_the_querystring() -// { -// var request = CreateRequest(); -// request.IncludeDocs = true; - -// WithHttpRequestFor( -// request, -// req => req.RelativeUrl.ToUnescapedQuery().Should().Be("?include_docs=true")); -// } - -// [Fact] -// public void When_IncludeDocs_is_assigned_false_It_should_get_included_in_the_querystring() -// { -// var request = CreateRequest(); -// request.IncludeDocs = false; - -// WithHttpRequestFor( -// request, -// req => req.RelativeUrl.ToUnescapedQuery().Should().Be("?include_docs=false")); -// } - -// [Fact] -// public void When_Stale_is_assigned_It_should_get_included_in_the_querystring() -// { -// var request = CreateRequest(); -// request.Stale = Stale.UpdateAfter; - -// WithHttpRequestFor( -// request, -// req => req.RelativeUrl.ToUnescapedQuery().Should().Be("?stale=update_after")); -// } - -// [Fact] -// public void When_Limit_is_assigned_It_should_get_included_in_the_querystring() -// { -// var request = CreateRequest(); -// request.Limit = 17; - -// WithHttpRequestFor( -// request, -// req => req.RelativeUrl.ToUnescapedQuery().Should().Be("?limit=17")); -// } - -// [Fact] -// public void When_Sort_is_assigned_It_should_get_included_in_the_querystring() -// { -// var request = CreateRequest(); -// request.Sort = new[] { "a", "b" }; - -// WithHttpRequestFor( -// request, -// req => req.RelativeUrl.ToUnescapedQuery().Should().Be("?sort=[\"a\",\"b\"]")); -// } - -// [Fact] -// public void When_GroupSort_is_assigned_It_should_get_included_in_the_querystring() -// { -// var request = CreateRequest(); -// request.GroupSort = new[] { "a", "b" }; - -// WithHttpRequestFor( -// request, -// req => req.RelativeUrl.ToUnescapedQuery().Should().Be("?group_sort=[\"a\",\"b\"]")); -// } - -// [Fact] -// public void When_GroupLimit_is_assigned_It_should_get_included_in_the_querystring() -// { -// var request = CreateRequest(); -// request.GroupLimit = 17; - -// WithHttpRequestFor( -// request, -// req => req.RelativeUrl.ToUnescapedQuery().Should().Be("?group_limit=17")); -// } - -// [Fact] -// public void When_GroupField_is_assigned_It_should_get_included_in_the_querystring() -// { -// var request = CreateRequest(); -// request.GroupField = "Some value"; - -// WithHttpRequestFor( -// request, -// req => req.RelativeUrl.ToUnescapedQuery().Should().Be("?group_field=Some value")); -// } - -// [Fact] -// public void When_more_than_one_option_is_configured_It_yields_a_query_string_accordingly() -// { -// var request = CreateRequest(); -// request.Expression = "class:mammal"; -// request.IncludeDocs = true; -// request.Limit = 10; -// request.Sort = new[] { "diet", "-min_length" }; - -// WithHttpRequestFor( -// request, -// req => req.RelativeUrl.ToUnescapedQuery().Should().Be("?q=class:mammal&sort=[\"diet\",\"-min_length\"]&limit=10&include_docs=true")); -// } - -// [Fact] -// public void When_Counts_is_assigned_It_should_get_included_in_the_querystring() -// { -// var request = CreateRequest(); -// request.Counts = new[] { "a", "b" }; - -// WithHttpRequestFor( -// request, -// req => req.RelativeUrl.ToUnescapedQuery().Should().Be("?counts=[\"a\",\"b\"]")); -// } - -// protected virtual SearchIndexRequest CreateRequest() -// { -// return new SearchIndexRequest("foodesigndoc", "indexname"); -// } - -// protected virtual void WithHttpRequestFor(SearchIndexRequest request, Action a) -// { -// var req = SUT.Create(request); -// a(req); -// } -// } -//} \ No newline at end of file +using System; +using FluentAssertions; +using MyCouch; +using MyCouch.HttpRequestFactories; +using MyCouch.Net; +using MyCouch.Requests; +using MyCouch.Testing; +using Xunit; + +namespace UnitTests.HttpRequestFactories +{ + public class SearchIndexHttpRequestFactoryTests : UnitTestsOf + { + public SearchIndexHttpRequestFactoryTests() + { + var boostrapper = new MyCouchClientBootstrapper(); + SUT = new SearchIndexHttpRequestFactory(boostrapper.SerializerFn()); + } + + [Fact] + public void When_not_configured_It_yields_no_content_nor_querystring() + { + var request = CreateRequest(); + + WithHttpRequestFor( + request, + req => + { + req.Content.Should().BeNull(); + req.RelativeUrl.ToUnescapedQuery().Should().Be(string.Empty); + }); + } + + [Fact] + public void When_Expression_is_assigned_It_should_get_included_in_the_querystring() + { + var request = CreateRequest(); + request.Expression = "Some value"; + + WithHttpRequestFor( + request, + req => req.RelativeUrl.ToUnescapedQuery().Should().Be("?q=Some value")); + } + + [Fact] + public void When_Bookmark_is_assigned_It_should_get_included_in_the_querystring() + { + var request = CreateRequest(); + request.Bookmark = "g1AAAADOeJzLYWBgYM5gTmGQT0lKzi9KdUhJMtbLSs1LLUst0kvOyS9NScwr0ctLLckBKmRKZEiy____f1YGk5v9l1kRDUCxRCaideexAEmGBiAFNGM_2JBvNSdBYomMJBpyAGLIfxRDmLIAxz9DAg"; + + WithHttpRequestFor( + request, + req => req.RelativeUrl.ToUnescapedQuery().Should().Be("?bookmark=g1AAAADOeJzLYWBgYM5gTmGQT0lKzi9KdUhJMtbLSs1LLUst0kvOyS9NScwr0ctLLckBKmRKZEiy____f1YGk5v9l1kRDUCxRCaideexAEmGBiAFNGM_2JBvNSdBYomMJBpyAGLIfxRDmLIAxz9DAg")); + } + + [Fact] + public void When_IncludeDocs_is_assigned_true_It_should_get_included_in_the_querystring() + { + var request = CreateRequest(); + request.IncludeDocs = true; + + WithHttpRequestFor( + request, + req => req.RelativeUrl.ToUnescapedQuery().Should().Be("?include_docs=true")); + } + + [Fact] + public void When_IncludeDocs_is_assigned_false_It_should_get_included_in_the_querystring() + { + var request = CreateRequest(); + request.IncludeDocs = false; + + WithHttpRequestFor( + request, + req => req.RelativeUrl.ToUnescapedQuery().Should().Be("?include_docs=false")); + } + + [Fact] + public void When_Stale_is_assigned_It_should_get_included_in_the_querystring() + { + var request = CreateRequest(); + request.Stale = Stale.UpdateAfter; + + WithHttpRequestFor( + request, + req => req.RelativeUrl.ToUnescapedQuery().Should().Be("?stale=update_after")); + } + + [Fact] + public void When_Limit_is_assigned_It_should_get_included_in_the_querystring() + { + var request = CreateRequest(); + request.Limit = 17; + + WithHttpRequestFor( + request, + req => req.RelativeUrl.ToUnescapedQuery().Should().Be("?limit=17")); + } + + [Fact] + public void When_Sort_is_assigned_It_should_get_included_in_the_querystring() + { + var request = CreateRequest(); + request.Sort = new[] { "a", "b" }; + + WithHttpRequestFor( + request, + req => req.RelativeUrl.ToUnescapedQuery().Should().Be("?sort=[\"a\",\"b\"]")); + } + + [Fact] + public void When_GroupSort_is_assigned_It_should_get_included_in_the_querystring() + { + var request = CreateRequest(); + request.GroupSort = new[] { "a", "b" }; + + WithHttpRequestFor( + request, + req => req.RelativeUrl.ToUnescapedQuery().Should().Be("?group_sort=[\"a\",\"b\"]")); + } + + [Fact] + public void When_GroupLimit_is_assigned_It_should_get_included_in_the_querystring() + { + var request = CreateRequest(); + request.GroupLimit = 17; + + WithHttpRequestFor( + request, + req => req.RelativeUrl.ToUnescapedQuery().Should().Be("?group_limit=17")); + } + + [Fact] + public void When_GroupField_is_assigned_It_should_get_included_in_the_querystring() + { + var request = CreateRequest(); + request.GroupField = "Some value"; + + WithHttpRequestFor( + request, + req => req.RelativeUrl.ToUnescapedQuery().Should().Be("?group_field=Some value")); + } + + [Fact] + public void When_more_than_one_option_is_configured_It_yields_a_query_string_accordingly() + { + var request = CreateRequest(); + request.Expression = "class:mammal"; + request.IncludeDocs = true; + request.Limit = 10; + request.Sort = new[] { "diet", "-min_length" }; + + WithHttpRequestFor( + request, + req => req.RelativeUrl.ToUnescapedQuery().Should().Be("?q=class:mammal&sort=[\"diet\",\"-min_length\"]&limit=10&include_docs=true")); + } + + [Fact] + public void When_Counts_is_assigned_It_should_get_included_in_the_querystring() + { + var request = CreateRequest(); + request.Counts = new[] { "a", "b" }; + + WithHttpRequestFor( + request, + req => req.RelativeUrl.ToUnescapedQuery().Should().Be("?counts=[\"a\",\"b\"]")); + } + + protected virtual SearchIndexRequest CreateRequest() + { + return new SearchIndexRequest("foodesigndoc", "indexname"); + } + + protected virtual void WithHttpRequestFor(SearchIndexRequest request, Action a) + { + var req = SUT.Create(request); + a(req); + } + } +} \ No newline at end of file diff --git a/source/tests/UnitTests/Responses/SearchIndexResponseTests.cs b/source/tests/UnitTests/Responses/SearchIndexResponseTests.cs index 1531350d..5984f9bc 100644 --- a/source/tests/UnitTests/Responses/SearchIndexResponseTests.cs +++ b/source/tests/UnitTests/Responses/SearchIndexResponseTests.cs @@ -1,26 +1,26 @@ -//using FluentAssertions; -//using MyCouch.Responses; -//using Xunit; +using FluentAssertions; +using MyCouch.Responses; +using Xunit; -//namespace UnitTests.Responses -//{ -// public class SearchIndexResponseTests : UnitTestsOf -// { -// [Fact] -// public void When_order_is_array_of_doubles_GetOrderAsDoubles_returns_doubles() -// { -// SUT = new SearchIndexResponse -// { -// Rows = new[] -// { -// new SearchIndexResponse.Row -// { -// Order = new object[] { 1.2, 1.3 } -// } -// } -// }; +namespace UnitTests.Responses +{ + public class SearchIndexResponseTests : UnitTestsOf + { + [Fact] + public void When_order_is_array_of_doubles_GetOrderAsDoubles_returns_doubles() + { + SUT = new SearchIndexResponse + { + Rows = new[] + { + new SearchIndexResponse.Row + { + Order = new object[] { 1.2, 1.3 } + } + } + }; -// SUT.Rows[0].GetOrderAsDoubles().Should().BeEquivalentTo(1.2, 1.3); -// } -// } -//} \ No newline at end of file + SUT.Rows[0].GetOrderAsDoubles().Should().BeEquivalentTo(1.2, 1.3); + } + } +} \ No newline at end of file diff --git a/source/tests/UnitTests/SearchParametersConfiguratorTests.cs b/source/tests/UnitTests/SearchParametersConfiguratorTests.cs index 1ae8e4ef..0731f5dd 100644 --- a/source/tests/UnitTests/SearchParametersConfiguratorTests.cs +++ b/source/tests/UnitTests/SearchParametersConfiguratorTests.cs @@ -1,157 +1,158 @@ -//using FluentAssertions; -//using MyCouch.Searching; -//using Xunit; +using FluentAssertions; +using MyCouch; +using MyCouch.Searching; +using Xunit; -//namespace UnitTests -//{ -// public class SearchParametersConfiguratorTests : UnitTestsOf -// { -// private readonly ISearchParameters _parameters; +namespace UnitTests +{ + public class SearchParametersConfiguratorTests : UnitTestsOf + { + private readonly ISearchParameters _parameters; -// public SearchParametersConfiguratorTests() -// { -// _parameters = new SearchParameters(new SearchIndexIdentity("foodesigndocument", "barindexname")); + public SearchParametersConfiguratorTests() + { + _parameters = new SearchParameters(new SearchIndexIdentity("foodesigndocument", "barindexname")); -// SUT = new SearchParametersConfigurator(_parameters); -// } + SUT = new SearchParametersConfigurator(_parameters); + } -// [Fact] -// public void When_config_of_Expression_of_string_It_configures_underlying_options_Expression() -// { -// const string configuredValue = "some value"; + [Fact] + public void When_config_of_Expression_of_string_It_configures_underlying_options_Expression() + { + const string configuredValue = "some value"; -// SUT.Expression(configuredValue); + SUT.Expression(configuredValue); -// _parameters.Expression.Should().Be(configuredValue); -// } + _parameters.Expression.Should().Be(configuredValue); + } -// [Fact] -// public void When_config_of_Bookmark_of_string_It_configures_underlying_options_Bookmark() -// { -// const string configuredValue = "g1AAAADOeJzLYWBgYM5gTmGQT0lKzi9KdUhJMtbLSs1LLUst0kvOyS9NScwr0ctLLckBKmRKZEiy____f1YGk5v9l1kRDUCxRCaideexAEmGBiAFNGM_2JBvNSdBYomMJBpyAGLIfxRDmLIAxz9DAg"; + [Fact] + public void When_config_of_Bookmark_of_string_It_configures_underlying_options_Bookmark() + { + const string configuredValue = "g1AAAADOeJzLYWBgYM5gTmGQT0lKzi9KdUhJMtbLSs1LLUst0kvOyS9NScwr0ctLLckBKmRKZEiy____f1YGk5v9l1kRDUCxRCaideexAEmGBiAFNGM_2JBvNSdBYomMJBpyAGLIfxRDmLIAxz9DAg"; -// SUT.Bookmark(configuredValue); + SUT.Bookmark(configuredValue); -// _parameters.Bookmark.Should().Be(configuredValue); -// } + _parameters.Bookmark.Should().Be(configuredValue); + } -// [Fact] -// public void When_config_of_Sort_It_configures_underlying_options_Sort() -// { -// var configuredValue = new [] { "diet", "latin_name", "min_length" }; + [Fact] + public void When_config_of_Sort_It_configures_underlying_options_Sort() + { + var configuredValue = new [] { "diet", "latin_name", "min_length" }; -// SUT.Sort(configuredValue); + SUT.Sort(configuredValue); -// _parameters.Sort.Should().ContainInOrder(configuredValue); -// } + _parameters.Sort.Should().ContainInOrder(configuredValue); + } -// [Fact] -// public void When_config_of_Sort_which_already_is_configures_It_uses_the_last_value_to_configure_underlying_options_Sort() -// { -// var configuredValue1 = new[] { "diet", "latin_name", "min_length" }; -// var configuredValue2 = new[] { "-diet", "-latin_name", "-min_length" }; + [Fact] + public void When_config_of_Sort_which_already_is_configures_It_uses_the_last_value_to_configure_underlying_options_Sort() + { + var configuredValue1 = new[] { "diet", "latin_name", "min_length" }; + var configuredValue2 = new[] { "-diet", "-latin_name", "-min_length" }; -// SUT.Sort(configuredValue1); -// SUT.Sort(configuredValue2); + SUT.Sort(configuredValue1); + SUT.Sort(configuredValue2); -// _parameters.Sort.Should().ContainInOrder(configuredValue2); -// } + _parameters.Sort.Should().ContainInOrder(configuredValue2); + } -// [Fact] -// public void When_config_of_IncludeDocs_It_configures_underlying_options_IncludeDocs() -// { -// const bool configuredValue = true; + [Fact] + public void When_config_of_IncludeDocs_It_configures_underlying_options_IncludeDocs() + { + const bool configuredValue = true; -// SUT.IncludeDocs(configuredValue); + SUT.IncludeDocs(configuredValue); -// _parameters.IncludeDocs.Should().Be(configuredValue); -// } + _parameters.IncludeDocs.Should().Be(configuredValue); + } -// [Fact] -// public void When_config_of_Stale_It_configures_underlying_options_Stale() -// { -// var configuredValue = Stale.UpdateAfter; + [Fact] + public void When_config_of_Stale_It_configures_underlying_options_Stale() + { + var configuredValue = Stale.UpdateAfter; -// SUT.Stale(configuredValue); + SUT.Stale(configuredValue); -// _parameters.Stale.Should().Be(configuredValue); -// } + _parameters.Stale.Should().Be(configuredValue); + } -// [Fact] -// public void When_config_of_Limit_It_configures_underlying_options_Limit() -// { -// const int configuredValue = 10; + [Fact] + public void When_config_of_Limit_It_configures_underlying_options_Limit() + { + const int configuredValue = 10; -// SUT.Limit(configuredValue); + SUT.Limit(configuredValue); -// _parameters.Limit.Should().Be(configuredValue); -// } + _parameters.Limit.Should().Be(configuredValue); + } -// [Fact] -// public void When_config_of_GroupField_It_configures_underlying_options_GroupField() -// { -// const string configuredValue = "name"; + [Fact] + public void When_config_of_GroupField_It_configures_underlying_options_GroupField() + { + const string configuredValue = "name"; -// SUT.GroupField(configuredValue); + SUT.GroupField(configuredValue); -// _parameters.GroupField.Should().Be(configuredValue); -// } + _parameters.GroupField.Should().Be(configuredValue); + } -// [Fact] -// public void When_config_of_GroupLimit_It_configures_underlying_options_GroupLimit() -// { -// const int configuredValue = 10; + [Fact] + public void When_config_of_GroupLimit_It_configures_underlying_options_GroupLimit() + { + const int configuredValue = 10; -// SUT.GroupLimit(configuredValue); + SUT.GroupLimit(configuredValue); -// _parameters.GroupLimit.Should().Be(configuredValue); -// } + _parameters.GroupLimit.Should().Be(configuredValue); + } -// [Fact] -// public void When_config_of_GroupSort_It_configures_underlying_options_GroupSort() -// { -// var configuredValue = new[] { "a", "b", "c" }; + [Fact] + public void When_config_of_GroupSort_It_configures_underlying_options_GroupSort() + { + var configuredValue = new[] { "a", "b", "c" }; -// SUT.GroupSort(configuredValue); + SUT.GroupSort(configuredValue); -// _parameters.GroupSort.Should().ContainInOrder(configuredValue); -// } + _parameters.GroupSort.Should().ContainInOrder(configuredValue); + } -// [Fact] -// public void When_config_of_Counts_It_configures_underlying_options_Counts() -// { -// var configuredValue = new[] { "a", "b", "c" }; + [Fact] + public void When_config_of_Counts_It_configures_underlying_options_Counts() + { + var configuredValue = new[] { "a", "b", "c" }; -// SUT.Counts(configuredValue); + SUT.Counts(configuredValue); -// _parameters.Counts.Should().ContainInOrder(configuredValue); -// } + _parameters.Counts.Should().ContainInOrder(configuredValue); + } -// [Fact] -// public void When_config_of_Ranges_It_configures_underlying_options_Ranges() -// { -// var configuredValue = new -// { -// min_length = new { minlight = "[0 TO 100]", minheavy = "{101 TO Infinity}" }, -// max_length = new { maxlight = "[0 TO 100]", maxheavy = "{101 TO Infinity}" } -// }; + [Fact] + public void When_config_of_Ranges_It_configures_underlying_options_Ranges() + { + var configuredValue = new + { + min_length = new { minlight = "[0 TO 100]", minheavy = "{101 TO Infinity}" }, + max_length = new { maxlight = "[0 TO 100]", maxheavy = "{101 TO Infinity}" } + }; -// SUT.Ranges(configuredValue); + SUT.Ranges(configuredValue); -// _parameters.Ranges.Should().BeSameAs(configuredValue); -// } + _parameters.Ranges.Should().BeSameAs(configuredValue); + } -// [Fact] -// public void When_config_of_DrillDown_It_configures_underlying_DrillDown() -// { -// var configuredfieldName = "configuredfieldName"; -// var configuredfieldValue = "configuredfielValue"; + [Fact] + public void When_config_of_DrillDown_It_configures_underlying_DrillDown() + { + var configuredfieldName = "configuredfieldName"; + var configuredfieldValue = "configuredfielValue"; -// SUT.DrillDown(configuredfieldName, configuredfieldValue); + SUT.DrillDown(configuredfieldName, configuredfieldValue); -// _parameters.DrillDown.Should().NotBeNull(); -// _parameters.DrillDown.Value.Key.Should().Be(configuredfieldName); -// _parameters.DrillDown.Value.Value.Should().Be(configuredfieldValue); -// } -// } -//} \ No newline at end of file + _parameters.DrillDown.Should().NotBeNull(); + _parameters.DrillDown.Value.Key.Should().Be(configuredfieldName); + _parameters.DrillDown.Value.Value.Should().Be(configuredfieldValue); + } + } +} \ No newline at end of file