diff --git a/src/Search/Microsoft.Azure.Search/Customizations/Serialization/Private/DoubleConverter.cs b/src/Search/Microsoft.Azure.Search/Customizations/Serialization/Private/DoubleConverter.cs new file mode 100644 index 000000000000..8b6925d42403 --- /dev/null +++ b/src/Search/Microsoft.Azure.Search/Customizations/Serialization/Private/DoubleConverter.cs @@ -0,0 +1,72 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for +// license information. + +namespace Microsoft.Azure.Search.Serialization +{ + using System; + using System.Globalization; + using System.Reflection; + using Newtonsoft.Json; + + /// + /// Serializes doubles to and from the OData wire format. + /// + internal class DoubleConverter : JsonConverter + { + private const string ODataNegativeInfinity = "-INF"; + private const string ODataPositiveInfinity = "INF"; + + public override bool CanConvert(Type objectType) => + typeof(double?).GetTypeInfo().IsAssignableFrom(objectType.GetTypeInfo()) || + typeof(double).GetTypeInfo().IsAssignableFrom(objectType.GetTypeInfo()); + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + if (reader.TokenType == JsonToken.Null) + { + return null; + } + + if (reader.TokenType == JsonToken.String) + { + string strValue = (string)reader.Value; + + switch (strValue) + { + case ODataPositiveInfinity: return Double.PositiveInfinity; + case ODataNegativeInfinity: return Double.NegativeInfinity; + default: return Double.Parse(strValue, CultureInfo.InvariantCulture); + } + } + + // We can't use a direct cast because sometimes we get integers from the reader. + return Convert.ToDouble(reader.Value); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + if (value == null) + { + writer.WriteNull(); + } + else + { + double doubleValue = (double)value; + + if (Double.IsNegativeInfinity(doubleValue)) + { + writer.WriteValue(ODataNegativeInfinity); + } + else if (Double.IsPositiveInfinity(doubleValue)) + { + writer.WriteValue(ODataPositiveInfinity); + } + else + { + writer.WriteValue(doubleValue); + } + } + } + } +} diff --git a/src/Search/Microsoft.Azure.Search/Customizations/Serialization/Private/JsonUtility.cs b/src/Search/Microsoft.Azure.Search/Customizations/Serialization/Private/JsonUtility.cs index 4f75a687aef0..15bb3a7cd35d 100644 --- a/src/Search/Microsoft.Azure.Search/Customizations/Serialization/Private/JsonUtility.cs +++ b/src/Search/Microsoft.Azure.Search/Customizations/Serialization/Private/JsonUtility.cs @@ -48,6 +48,7 @@ private static JsonSerializerSettings CreateSerializerSettings( settings.Converters.Add(new GeographyPointConverter()); settings.Converters.Add(new IndexActionConverter()); settings.Converters.Add(new DateTimeConverter()); + settings.Converters.Add(new DoubleConverter()); settings.NullValueHandling = NullValueHandling.Ignore; if (useCamelCase) @@ -72,6 +73,7 @@ private static JsonSerializerSettings CreateDeserializerSettings()); settings.Converters.Add(new SuggestResultConverter()); settings.DateParseHandling = DateParseHandling.DateTimeOffset; diff --git a/src/Search/Search.Tests/SessionRecords/Microsoft.Azure.Search.Tests.IndexingTests/CanRoundtripBoundaryValues.json b/src/Search/Search.Tests/SessionRecords/Microsoft.Azure.Search.Tests.IndexingTests/CanRoundtripBoundaryValues.json new file mode 100644 index 000000000000..23d5a70ea5a7 --- /dev/null +++ b/src/Search/Search.Tests/SessionRecords/Microsoft.Azure.Search.Tests.IndexingTests/CanRoundtripBoundaryValues.json @@ -0,0 +1,911 @@ +{ + "Entries": [ + { + "RequestUri": "/subscriptions/b80cf239-2c72-47ab-b309-b26aec4656b1/providers/Microsoft.Search/register?api-version=2016-02-01", + "EncodedRequestUri": "L3N1YnNjcmlwdGlvbnMvYjgwY2YyMzktMmM3Mi00N2FiLWIzMDktYjI2YWVjNDY1NmIxL3Byb3ZpZGVycy9NaWNyb3NvZnQuU2VhcmNoL3JlZ2lzdGVyP2FwaS12ZXJzaW9uPTIwMTYtMDItMDE=", + "RequestMethod": "POST", + "RequestBody": "", + "RequestHeaders": { + "x-ms-client-request-id": [ + "c39b2c79-8770-4cd2-bd1b-b514a3a20070" + ], + "accept-language": [ + "en-US" + ], + "User-Agent": [ + "FxVersion/4.6.24214.01", + "Microsoft.Azure.Management.ResourceManager.ResourceManagementClient/1.1.1-preview" + ] + }, + "ResponseBody": "{\r\n \"id\": \"/subscriptions/b80cf239-2c72-47ab-b309-b26aec4656b1/providers/Microsoft.Search\",\r\n \"namespace\": \"Microsoft.Search\",\r\n \"resourceTypes\": [\r\n {\r\n \"resourceType\": \"searchServices\",\r\n \"locations\": [\r\n \"West US\"\r\n ],\r\n \"apiVersions\": [\r\n \"2015-08-19\",\r\n \"2015-02-28\",\r\n \"2014-07-31-Preview\"\r\n ],\r\n \"capabilities\": \"CrossResourceGroupResourceMove, CrossSubscriptionResourceMove\"\r\n },\r\n {\r\n \"resourceType\": \"searchServicesCit\",\r\n \"locations\": [\r\n \"West US\"\r\n ],\r\n \"apiVersions\": [\r\n \"2015-08-19\",\r\n \"2015-02-28\",\r\n \"2014-07-31-Preview\"\r\n ],\r\n \"capabilities\": \"CrossResourceGroupResourceMove, CrossSubscriptionResourceMove\"\r\n },\r\n {\r\n \"resourceType\": \"searchServicesNxt\",\r\n \"locations\": [\r\n \"West US\"\r\n ],\r\n \"apiVersions\": [\r\n \"2015-08-19\",\r\n \"2015-02-28\",\r\n \"2014-07-31-Preview\"\r\n ],\r\n \"capabilities\": \"CrossResourceGroupResourceMove, CrossSubscriptionResourceMove\"\r\n },\r\n {\r\n \"resourceType\": \"searchServicesInt\",\r\n \"locations\": [\r\n \"West US\"\r\n ],\r\n \"apiVersions\": [\r\n \"2015-08-19\",\r\n \"2015-02-28\",\r\n \"2014-07-31-Preview\"\r\n ],\r\n \"capabilities\": \"CrossResourceGroupResourceMove, CrossSubscriptionResourceMove\"\r\n },\r\n {\r\n \"resourceType\": \"searchServicesPpe\",\r\n \"locations\": [\r\n \"West US\"\r\n ],\r\n \"apiVersions\": [\r\n \"2015-08-19\",\r\n \"2015-02-28\",\r\n \"2014-07-31-Preview\"\r\n ],\r\n \"capabilities\": \"CrossResourceGroupResourceMove, CrossSubscriptionResourceMove\"\r\n },\r\n {\r\n \"resourceType\": \"checkServiceNameAvailability\",\r\n \"locations\": [],\r\n \"apiVersions\": [\r\n \"2015-02-28\",\r\n \"2014-07-31-Preview\"\r\n ]\r\n },\r\n {\r\n \"resourceType\": \"checkServiceNameAvailabilityCit\",\r\n \"locations\": [],\r\n \"apiVersions\": [\r\n \"2015-02-28\",\r\n \"2014-07-31-Preview\"\r\n ]\r\n },\r\n {\r\n \"resourceType\": \"checkServiceNameAvailabilityNxt\",\r\n \"locations\": [],\r\n \"apiVersions\": [\r\n \"2015-02-28\",\r\n \"2014-07-31-Preview\"\r\n ]\r\n },\r\n {\r\n \"resourceType\": \"checkServiceNameAvailabilityInt\",\r\n \"locations\": [],\r\n \"apiVersions\": [\r\n \"2015-02-28\",\r\n \"2014-07-31-Preview\"\r\n ]\r\n },\r\n {\r\n \"resourceType\": \"checkServiceNameAvailabilityPpe\",\r\n \"locations\": [],\r\n \"apiVersions\": [\r\n \"2015-02-28\",\r\n \"2014-07-31-Preview\"\r\n ]\r\n },\r\n {\r\n \"resourceType\": \"checkNameAvailability\",\r\n \"locations\": [],\r\n \"apiVersions\": [\r\n \"2015-08-19\"\r\n ]\r\n },\r\n {\r\n \"resourceType\": \"checkNameAvailabilityCit\",\r\n \"locations\": [],\r\n \"apiVersions\": [\r\n \"2015-08-19\"\r\n ]\r\n },\r\n {\r\n \"resourceType\": \"checkNameAvailabilityNxt\",\r\n \"locations\": [],\r\n \"apiVersions\": [\r\n \"2015-08-19\"\r\n ]\r\n },\r\n {\r\n \"resourceType\": \"checkNameAvailabilityInt\",\r\n \"locations\": [],\r\n \"apiVersions\": [\r\n \"2015-08-19\"\r\n ]\r\n },\r\n {\r\n \"resourceType\": \"checkNameAvailabilityPpe\",\r\n \"locations\": [],\r\n \"apiVersions\": [\r\n \"2015-08-19\"\r\n ]\r\n },\r\n {\r\n \"resourceType\": \"resourceHealthMetadata\",\r\n \"locations\": [],\r\n \"apiVersions\": [\r\n \"2015-08-19\"\r\n ]\r\n },\r\n {\r\n \"resourceType\": \"operations\",\r\n \"locations\": [],\r\n \"apiVersions\": [\r\n \"2015-08-19\",\r\n \"2015-02-28\"\r\n ]\r\n }\r\n ],\r\n \"registrationState\": \"Registered\"\r\n}", + "ResponseHeaders": { + "Content-Type": [ + "application/json; charset=utf-8" + ], + "Expires": [ + "-1" + ], + "Cache-Control": [ + "no-cache" + ], + "Date": [ + "Thu, 23 Feb 2017 03:50:25 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Vary": [ + "Accept-Encoding" + ], + "x-ms-ratelimit-remaining-subscription-writes": [ + "1178" + ], + "x-ms-request-id": [ + "c49ddea8-afaa-455e-bea4-7097248a0625" + ], + "x-ms-correlation-request-id": [ + "c49ddea8-afaa-455e-bea4-7097248a0625" + ], + "x-ms-routing-request-id": [ + "CENTRALUS:20170223T035025Z:c49ddea8-afaa-455e-bea4-7097248a0625" + ], + "Strict-Transport-Security": [ + "max-age=31536000; includeSubDomains" + ] + }, + "StatusCode": 200 + }, + { + "RequestUri": "/subscriptions/b80cf239-2c72-47ab-b309-b26aec4656b1/resourcegroups/azsmnet5916?api-version=2016-02-01", + "EncodedRequestUri": "L3N1YnNjcmlwdGlvbnMvYjgwY2YyMzktMmM3Mi00N2FiLWIzMDktYjI2YWVjNDY1NmIxL3Jlc291cmNlZ3JvdXBzL2F6c21uZXQ1OTE2P2FwaS12ZXJzaW9uPTIwMTYtMDItMDE=", + "RequestMethod": "PUT", + "RequestBody": "{\r\n \"location\": \"West US\"\r\n}", + "RequestHeaders": { + "Content-Type": [ + "application/json; charset=utf-8" + ], + "Content-Length": [ + "29" + ], + "x-ms-client-request-id": [ + "63b97228-c6b2-4780-8602-c6d54bd79b9e" + ], + "accept-language": [ + "en-US" + ], + "User-Agent": [ + "FxVersion/4.6.24214.01", + "Microsoft.Azure.Management.ResourceManager.ResourceManagementClient/1.1.1-preview" + ] + }, + "ResponseBody": "{\r\n \"id\": \"/subscriptions/b80cf239-2c72-47ab-b309-b26aec4656b1/resourceGroups/azsmnet5916\",\r\n \"name\": \"azsmnet5916\",\r\n \"location\": \"westus\",\r\n \"properties\": {\r\n \"provisioningState\": \"Succeeded\"\r\n }\r\n}", + "ResponseHeaders": { + "Content-Length": [ + "175" + ], + "Content-Type": [ + "application/json; charset=utf-8" + ], + "Expires": [ + "-1" + ], + "Cache-Control": [ + "no-cache" + ], + "Date": [ + "Thu, 23 Feb 2017 03:50:25 GMT" + ], + "Pragma": [ + "no-cache" + ], + "x-ms-ratelimit-remaining-subscription-writes": [ + "1177" + ], + "x-ms-request-id": [ + "7bee1f12-0756-4e24-b3c7-eac28aa7a704" + ], + "x-ms-correlation-request-id": [ + "7bee1f12-0756-4e24-b3c7-eac28aa7a704" + ], + "x-ms-routing-request-id": [ + "CENTRALUS:20170223T035025Z:7bee1f12-0756-4e24-b3c7-eac28aa7a704" + ], + "Strict-Transport-Security": [ + "max-age=31536000; includeSubDomains" + ] + }, + "StatusCode": 201 + }, + { + "RequestUri": "/subscriptions/b80cf239-2c72-47ab-b309-b26aec4656b1/resourceGroups/azsmnet5916/providers/Microsoft.Search/searchServices/azs-6259?api-version=2015-08-19", + "EncodedRequestUri": "L3N1YnNjcmlwdGlvbnMvYjgwY2YyMzktMmM3Mi00N2FiLWIzMDktYjI2YWVjNDY1NmIxL3Jlc291cmNlR3JvdXBzL2F6c21uZXQ1OTE2L3Byb3ZpZGVycy9NaWNyb3NvZnQuU2VhcmNoL3NlYXJjaFNlcnZpY2VzL2F6cy02MjU5P2FwaS12ZXJzaW9uPTIwMTUtMDgtMTk=", + "RequestMethod": "PUT", + "RequestBody": "{\r\n \"sku\": {\r\n \"name\": \"free\"\r\n },\r\n \"location\": \"West US\"\r\n}", + "RequestHeaders": { + "Content-Type": [ + "application/json; charset=utf-8" + ], + "Content-Length": [ + "67" + ], + "x-ms-client-request-id": [ + "1e11c9e7-1381-4ad3-a884-6ce04521d801" + ], + "accept-language": [ + "en-US" + ], + "User-Agent": [ + "FxVersion/4.6.24214.01", + "Microsoft.Azure.Management.Search.SearchManagementClient/1.0.1" + ] + }, + "ResponseBody": "{\r\n \"id\": \"/subscriptions/b80cf239-2c72-47ab-b309-b26aec4656b1/resourceGroups/azsmnet5916/providers/Microsoft.Search/searchServices/azs-6259\",\r\n \"name\": \"azs-6259\",\r\n \"type\": \"Microsoft.Search/searchServices\",\r\n \"location\": \"West US\",\r\n \"properties\": {\r\n \"replicaCount\": 1,\r\n \"partitionCount\": 1,\r\n \"status\": \"running\",\r\n \"statusDetails\": \"\",\r\n \"provisioningState\": \"succeeded\",\r\n \"hostingMode\": \"Default\"\r\n },\r\n \"sku\": {\r\n \"name\": \"free\"\r\n }\r\n}", + "ResponseHeaders": { + "Content-Length": [ + "385" + ], + "Content-Type": [ + "application/json; charset=utf-8" + ], + "Expires": [ + "-1" + ], + "Cache-Control": [ + "no-cache" + ], + "Date": [ + "Thu, 23 Feb 2017 03:50:27 GMT" + ], + "Pragma": [ + "no-cache" + ], + "ETag": [ + "W/\"datetime'2017-02-23T03%3A50%3A27.3715502Z'\"" + ], + "x-ms-request-id": [ + "1e11c9e7-1381-4ad3-a884-6ce04521d801" + ], + "request-id": [ + "1e11c9e7-1381-4ad3-a884-6ce04521d801" + ], + "elapsed-time": [ + "746" + ], + "Strict-Transport-Security": [ + "max-age=31536000; includeSubDomains" + ], + "X-AspNet-Version": [ + "4.0.30319" + ], + "x-ms-ratelimit-remaining-subscription-writes": [ + "1177" + ], + "x-ms-correlation-request-id": [ + "1e68f05d-a1f6-47be-a8e9-3f47fb1749d1" + ], + "x-ms-routing-request-id": [ + "CENTRALUS:20170223T035027Z:1e68f05d-a1f6-47be-a8e9-3f47fb1749d1" + ] + }, + "StatusCode": 201 + }, + { + "RequestUri": "/subscriptions/b80cf239-2c72-47ab-b309-b26aec4656b1/resourceGroups/azsmnet5916/providers/Microsoft.Search/searchServices/azs-6259/listAdminKeys?api-version=2015-08-19", + "EncodedRequestUri": "L3N1YnNjcmlwdGlvbnMvYjgwY2YyMzktMmM3Mi00N2FiLWIzMDktYjI2YWVjNDY1NmIxL3Jlc291cmNlR3JvdXBzL2F6c21uZXQ1OTE2L3Byb3ZpZGVycy9NaWNyb3NvZnQuU2VhcmNoL3NlYXJjaFNlcnZpY2VzL2F6cy02MjU5L2xpc3RBZG1pbktleXM/YXBpLXZlcnNpb249MjAxNS0wOC0xOQ==", + "RequestMethod": "POST", + "RequestBody": "", + "RequestHeaders": { + "x-ms-client-request-id": [ + "264bd365-40f0-465c-a29a-8d0430d3e607" + ], + "accept-language": [ + "en-US" + ], + "User-Agent": [ + "FxVersion/4.6.24214.01", + "Microsoft.Azure.Management.Search.SearchManagementClient/1.0.1" + ] + }, + "ResponseBody": "{\r\n \"primaryKey\": \"6EEAB44C598F49730C5789F5395F85AB\",\r\n \"secondaryKey\": \"4DFA12AB510A07A64B7ECBC37736A762\"\r\n}", + "ResponseHeaders": { + "Content-Type": [ + "application/json; charset=utf-8" + ], + "Expires": [ + "-1" + ], + "Cache-Control": [ + "no-cache" + ], + "Date": [ + "Thu, 23 Feb 2017 03:50:27 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Vary": [ + "Accept-Encoding", + "Accept-Encoding" + ], + "x-ms-request-id": [ + "264bd365-40f0-465c-a29a-8d0430d3e607" + ], + "request-id": [ + "264bd365-40f0-465c-a29a-8d0430d3e607" + ], + "elapsed-time": [ + "160" + ], + "Strict-Transport-Security": [ + "max-age=31536000; includeSubDomains" + ], + "X-AspNet-Version": [ + "4.0.30319" + ], + "x-ms-ratelimit-remaining-subscription-writes": [ + "1176" + ], + "x-ms-correlation-request-id": [ + "4eb000f6-48a3-4655-8e7a-d649324a70b3" + ], + "x-ms-routing-request-id": [ + "CENTRALUS:20170223T035028Z:4eb000f6-48a3-4655-8e7a-d649324a70b3" + ] + }, + "StatusCode": 200 + }, + { + "RequestUri": "/subscriptions/b80cf239-2c72-47ab-b309-b26aec4656b1/resourceGroups/azsmnet5916/providers/Microsoft.Search/searchServices/azs-6259/listQueryKeys?api-version=2015-08-19", + "EncodedRequestUri": "L3N1YnNjcmlwdGlvbnMvYjgwY2YyMzktMmM3Mi00N2FiLWIzMDktYjI2YWVjNDY1NmIxL3Jlc291cmNlR3JvdXBzL2F6c21uZXQ1OTE2L3Byb3ZpZGVycy9NaWNyb3NvZnQuU2VhcmNoL3NlYXJjaFNlcnZpY2VzL2F6cy02MjU5L2xpc3RRdWVyeUtleXM/YXBpLXZlcnNpb249MjAxNS0wOC0xOQ==", + "RequestMethod": "GET", + "RequestBody": "", + "RequestHeaders": { + "x-ms-client-request-id": [ + "6a0c924b-954b-41b4-8efa-220fba457122" + ], + "accept-language": [ + "en-US" + ], + "User-Agent": [ + "FxVersion/4.6.24214.01", + "Microsoft.Azure.Management.Search.SearchManagementClient/1.0.1" + ] + }, + "ResponseBody": "{\r\n \"value\": [\r\n {\r\n \"name\": null,\r\n \"key\": \"DB84FE4C40D0C1484AF23CF4162B6BEC\"\r\n }\r\n ],\r\n \"nextLink\": null\r\n}", + "ResponseHeaders": { + "Content-Type": [ + "application/json; charset=utf-8" + ], + "Expires": [ + "-1" + ], + "Cache-Control": [ + "no-cache" + ], + "Date": [ + "Thu, 23 Feb 2017 03:50:28 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Vary": [ + "Accept-Encoding", + "Accept-Encoding" + ], + "x-ms-request-id": [ + "6a0c924b-954b-41b4-8efa-220fba457122" + ], + "request-id": [ + "6a0c924b-954b-41b4-8efa-220fba457122" + ], + "elapsed-time": [ + "159" + ], + "Strict-Transport-Security": [ + "max-age=31536000; includeSubDomains" + ], + "X-AspNet-Version": [ + "4.0.30319" + ], + "x-ms-ratelimit-remaining-subscription-reads": [ + "14998" + ], + "x-ms-correlation-request-id": [ + "fbaad36d-a3e0-404e-b697-0298e9874f65" + ], + "x-ms-routing-request-id": [ + "CENTRALUS:20170223T035028Z:fbaad36d-a3e0-404e-b697-0298e9874f65" + ] + }, + "StatusCode": 200 + }, + { + "RequestUri": "/indexes?api-version=2016-09-01", + "EncodedRequestUri": "L2luZGV4ZXM/YXBpLXZlcnNpb249MjAxNi0wOS0wMQ==", + "RequestMethod": "POST", + "RequestBody": "{\r\n \"name\": \"azsmnet4790\",\r\n \"fields\": [\r\n {\r\n \"name\": \"hotelId\",\r\n \"type\": \"Edm.String\",\r\n \"key\": true,\r\n \"searchable\": false,\r\n \"filterable\": true,\r\n \"sortable\": true,\r\n \"facetable\": true,\r\n \"retrievable\": true\r\n },\r\n {\r\n \"name\": \"baseRate\",\r\n \"type\": \"Edm.Double\",\r\n \"key\": false,\r\n \"searchable\": false,\r\n \"filterable\": true,\r\n \"sortable\": true,\r\n \"facetable\": true,\r\n \"retrievable\": true\r\n },\r\n {\r\n \"name\": \"description\",\r\n \"type\": \"Edm.String\",\r\n \"key\": false,\r\n \"searchable\": true,\r\n \"filterable\": false,\r\n \"sortable\": false,\r\n \"facetable\": false,\r\n \"retrievable\": true\r\n },\r\n {\r\n \"name\": \"descriptionFr\",\r\n \"type\": \"Edm.String\",\r\n \"analyzer\": \"fr.lucene\",\r\n \"key\": false,\r\n \"searchable\": true,\r\n \"filterable\": false,\r\n \"sortable\": false,\r\n \"facetable\": false,\r\n \"retrievable\": true\r\n },\r\n {\r\n \"name\": \"hotelName\",\r\n \"type\": \"Edm.String\",\r\n \"key\": false,\r\n \"searchable\": true,\r\n \"filterable\": true,\r\n \"sortable\": true,\r\n \"facetable\": true,\r\n \"retrievable\": true\r\n },\r\n {\r\n \"name\": \"category\",\r\n \"type\": \"Edm.String\",\r\n \"key\": false,\r\n \"searchable\": true,\r\n \"filterable\": true,\r\n \"sortable\": true,\r\n \"facetable\": true,\r\n \"retrievable\": true\r\n },\r\n {\r\n \"name\": \"tags\",\r\n \"type\": \"Collection(Edm.String)\",\r\n \"key\": false,\r\n \"searchable\": true,\r\n \"filterable\": true,\r\n \"sortable\": false,\r\n \"facetable\": true,\r\n \"retrievable\": true\r\n },\r\n {\r\n \"name\": \"parkingIncluded\",\r\n \"type\": \"Edm.Boolean\",\r\n \"key\": false,\r\n \"searchable\": false,\r\n \"filterable\": true,\r\n \"sortable\": true,\r\n \"facetable\": true,\r\n \"retrievable\": true\r\n },\r\n {\r\n \"name\": \"smokingAllowed\",\r\n \"type\": \"Edm.Boolean\",\r\n \"key\": false,\r\n \"searchable\": false,\r\n \"filterable\": true,\r\n \"sortable\": true,\r\n \"facetable\": true,\r\n \"retrievable\": true\r\n },\r\n {\r\n \"name\": \"lastRenovationDate\",\r\n \"type\": \"Edm.DateTimeOffset\",\r\n \"key\": false,\r\n \"searchable\": false,\r\n \"filterable\": true,\r\n \"sortable\": true,\r\n \"facetable\": true,\r\n \"retrievable\": true\r\n },\r\n {\r\n \"name\": \"rating\",\r\n \"type\": \"Edm.Int32\",\r\n \"key\": false,\r\n \"searchable\": false,\r\n \"filterable\": true,\r\n \"sortable\": true,\r\n \"facetable\": true,\r\n \"retrievable\": true\r\n },\r\n {\r\n \"name\": \"location\",\r\n \"type\": \"Edm.GeographyPoint\",\r\n \"key\": false,\r\n \"searchable\": false,\r\n \"filterable\": true,\r\n \"sortable\": true,\r\n \"facetable\": false,\r\n \"retrievable\": true\r\n }\r\n ],\r\n \"scoringProfiles\": [\r\n {\r\n \"name\": \"nearest\",\r\n \"functions\": [\r\n {\r\n \"type\": \"distance\",\r\n \"distance\": {\r\n \"referencePointParameter\": \"myloc\",\r\n \"boostingDistance\": 100.0\r\n },\r\n \"fieldName\": \"location\",\r\n \"boost\": 2.0\r\n }\r\n ],\r\n \"functionAggregation\": \"sum\"\r\n }\r\n ],\r\n \"suggesters\": [\r\n {\r\n \"name\": \"sg\",\r\n \"searchMode\": \"analyzingInfixMatching\",\r\n \"sourceFields\": [\r\n \"description\",\r\n \"hotelName\"\r\n ]\r\n }\r\n ]\r\n}", + "RequestHeaders": { + "Content-Type": [ + "application/json; charset=utf-8" + ], + "Content-Length": [ + "3401" + ], + "client-request-id": [ + "76b3783f-388b-4283-9451-ce5dc20bcf56" + ], + "accept-language": [ + "en-US" + ], + "api-key": [ + "6EEAB44C598F49730C5789F5395F85AB" + ], + "Prefer": [ + "return=representation" + ], + "User-Agent": [ + "FxVersion/4.6.24214.01", + "Microsoft.Azure.Search.SearchServiceClient/3.0.2" + ] + }, + "ResponseBody": "{\r\n \"@odata.context\": \"https://azs-6259.search-dogfood.windows-int.net/$metadata#indexes/$entity\",\r\n \"@odata.etag\": \"\\\"0x8D45B9F1C8433D5\\\"\",\r\n \"name\": \"azsmnet4790\",\r\n \"fields\": [\r\n {\r\n \"name\": \"hotelId\",\r\n \"type\": \"Edm.String\",\r\n \"searchable\": false,\r\n \"filterable\": true,\r\n \"retrievable\": true,\r\n \"sortable\": true,\r\n \"facetable\": true,\r\n \"key\": true,\r\n \"indexAnalyzer\": null,\r\n \"searchAnalyzer\": null,\r\n \"analyzer\": null\r\n },\r\n {\r\n \"name\": \"baseRate\",\r\n \"type\": \"Edm.Double\",\r\n \"searchable\": false,\r\n \"filterable\": true,\r\n \"retrievable\": true,\r\n \"sortable\": true,\r\n \"facetable\": true,\r\n \"key\": false,\r\n \"indexAnalyzer\": null,\r\n \"searchAnalyzer\": null,\r\n \"analyzer\": null\r\n },\r\n {\r\n \"name\": \"description\",\r\n \"type\": \"Edm.String\",\r\n \"searchable\": true,\r\n \"filterable\": false,\r\n \"retrievable\": true,\r\n \"sortable\": false,\r\n \"facetable\": false,\r\n \"key\": false,\r\n \"indexAnalyzer\": null,\r\n \"searchAnalyzer\": null,\r\n \"analyzer\": null\r\n },\r\n {\r\n \"name\": \"descriptionFr\",\r\n \"type\": \"Edm.String\",\r\n \"searchable\": true,\r\n \"filterable\": false,\r\n \"retrievable\": true,\r\n \"sortable\": false,\r\n \"facetable\": false,\r\n \"key\": false,\r\n \"indexAnalyzer\": null,\r\n \"searchAnalyzer\": null,\r\n \"analyzer\": \"fr.lucene\"\r\n },\r\n {\r\n \"name\": \"hotelName\",\r\n \"type\": \"Edm.String\",\r\n \"searchable\": true,\r\n \"filterable\": true,\r\n \"retrievable\": true,\r\n \"sortable\": true,\r\n \"facetable\": true,\r\n \"key\": false,\r\n \"indexAnalyzer\": null,\r\n \"searchAnalyzer\": null,\r\n \"analyzer\": null\r\n },\r\n {\r\n \"name\": \"category\",\r\n \"type\": \"Edm.String\",\r\n \"searchable\": true,\r\n \"filterable\": true,\r\n \"retrievable\": true,\r\n \"sortable\": true,\r\n \"facetable\": true,\r\n \"key\": false,\r\n \"indexAnalyzer\": null,\r\n \"searchAnalyzer\": null,\r\n \"analyzer\": null\r\n },\r\n {\r\n \"name\": \"tags\",\r\n \"type\": \"Collection(Edm.String)\",\r\n \"searchable\": true,\r\n \"filterable\": true,\r\n \"retrievable\": true,\r\n \"sortable\": false,\r\n \"facetable\": true,\r\n \"key\": false,\r\n \"indexAnalyzer\": null,\r\n \"searchAnalyzer\": null,\r\n \"analyzer\": null\r\n },\r\n {\r\n \"name\": \"parkingIncluded\",\r\n \"type\": \"Edm.Boolean\",\r\n \"searchable\": false,\r\n \"filterable\": true,\r\n \"retrievable\": true,\r\n \"sortable\": true,\r\n \"facetable\": true,\r\n \"key\": false,\r\n \"indexAnalyzer\": null,\r\n \"searchAnalyzer\": null,\r\n \"analyzer\": null\r\n },\r\n {\r\n \"name\": \"smokingAllowed\",\r\n \"type\": \"Edm.Boolean\",\r\n \"searchable\": false,\r\n \"filterable\": true,\r\n \"retrievable\": true,\r\n \"sortable\": true,\r\n \"facetable\": true,\r\n \"key\": false,\r\n \"indexAnalyzer\": null,\r\n \"searchAnalyzer\": null,\r\n \"analyzer\": null\r\n },\r\n {\r\n \"name\": \"lastRenovationDate\",\r\n \"type\": \"Edm.DateTimeOffset\",\r\n \"searchable\": false,\r\n \"filterable\": true,\r\n \"retrievable\": true,\r\n \"sortable\": true,\r\n \"facetable\": true,\r\n \"key\": false,\r\n \"indexAnalyzer\": null,\r\n \"searchAnalyzer\": null,\r\n \"analyzer\": null\r\n },\r\n {\r\n \"name\": \"rating\",\r\n \"type\": \"Edm.Int32\",\r\n \"searchable\": false,\r\n \"filterable\": true,\r\n \"retrievable\": true,\r\n \"sortable\": true,\r\n \"facetable\": true,\r\n \"key\": false,\r\n \"indexAnalyzer\": null,\r\n \"searchAnalyzer\": null,\r\n \"analyzer\": null\r\n },\r\n {\r\n \"name\": \"location\",\r\n \"type\": \"Edm.GeographyPoint\",\r\n \"searchable\": false,\r\n \"filterable\": true,\r\n \"retrievable\": true,\r\n \"sortable\": true,\r\n \"facetable\": false,\r\n \"key\": false,\r\n \"indexAnalyzer\": null,\r\n \"searchAnalyzer\": null,\r\n \"analyzer\": null\r\n }\r\n ],\r\n \"scoringProfiles\": [\r\n {\r\n \"name\": \"nearest\",\r\n \"text\": null,\r\n \"functions\": [\r\n {\r\n \"fieldName\": \"location\",\r\n \"freshness\": null,\r\n \"interpolation\": \"linear\",\r\n \"magnitude\": null,\r\n \"distance\": {\r\n \"referencePointParameter\": \"myloc\",\r\n \"boostingDistance\": 100.0\r\n },\r\n \"tag\": null,\r\n \"type\": \"distance\",\r\n \"boost\": 2.0\r\n }\r\n ],\r\n \"functionAggregation\": \"sum\"\r\n }\r\n ],\r\n \"defaultScoringProfile\": null,\r\n \"corsOptions\": null,\r\n \"suggesters\": [\r\n {\r\n \"name\": \"sg\",\r\n \"searchMode\": \"analyzingInfixMatching\",\r\n \"sourceFields\": [\r\n \"description\",\r\n \"hotelName\"\r\n ]\r\n }\r\n ],\r\n \"analyzers\": [],\r\n \"tokenizers\": [],\r\n \"tokenFilters\": [],\r\n \"charFilters\": []\r\n}", + "ResponseHeaders": { + "Content-Length": [ + "3141" + ], + "Content-Type": [ + "application/json; odata.metadata=minimal" + ], + "Expires": [ + "-1" + ], + "Cache-Control": [ + "no-cache" + ], + "Date": [ + "Thu, 23 Feb 2017 03:50:30 GMT" + ], + "Pragma": [ + "no-cache" + ], + "ETag": [ + "W/\"0x8D45B9F1C8433D5\"" + ], + "Location": [ + "https://azs-6259.search-dogfood.windows-int.net/indexes('azsmnet4790')?api-version=2016-09-01" + ], + "request-id": [ + "76b3783f-388b-4283-9451-ce5dc20bcf56" + ], + "elapsed-time": [ + "922" + ], + "OData-Version": [ + "4.0" + ], + "Preference-Applied": [ + "odata.include-annotations=\"*\"" + ], + "Strict-Transport-Security": [ + "max-age=15724800; includeSubDomains" + ] + }, + "StatusCode": 201 + }, + { + "RequestUri": "/indexes('azsmnet4790')/docs/search.index?api-version=2016-09-01", + "EncodedRequestUri": "L2luZGV4ZXMoJ2F6c21uZXQ0NzkwJykvZG9jcy9zZWFyY2guaW5kZXg/YXBpLXZlcnNpb249MjAxNi0wOS0wMQ==", + "RequestMethod": "POST", + "RequestBody": "{\r\n \"value\": [\r\n {\r\n \"@search.action\": \"upload\",\r\n \"hotelId\": \"1\",\r\n \"baseRate\": -1.7976931348623157E+308,\r\n \"category\": \"\",\r\n \"tags\": [],\r\n \"parkingIncluded\": false,\r\n \"lastRenovationDate\": \"0001-01-01T00:00:00+00:00\",\r\n \"rating\": -2147483648,\r\n \"location\": {\r\n \"type\": \"Point\",\r\n \"coordinates\": [\r\n -180.0,\r\n -90.0\r\n ]\r\n }\r\n },\r\n {\r\n \"@search.action\": \"upload\",\r\n \"hotelId\": \"2\",\r\n \"baseRate\": 1.7976931348623157E+308,\r\n \"category\": \"test\",\r\n \"tags\": [\r\n \"test\"\r\n ],\r\n \"parkingIncluded\": true,\r\n \"lastRenovationDate\": \"9999-12-31T23:59:59.9999999+00:00\",\r\n \"rating\": 2147483647,\r\n \"location\": {\r\n \"type\": \"Point\",\r\n \"coordinates\": [\r\n 180.0,\r\n 90.0\r\n ]\r\n }\r\n },\r\n {\r\n \"@search.action\": \"upload\",\r\n \"hotelId\": \"3\",\r\n \"baseRate\": \"-INF\",\r\n \"tags\": [],\r\n \"location\": {\r\n \"type\": \"Point\",\r\n \"coordinates\": [\r\n 0.0,\r\n 0.0\r\n ]\r\n }\r\n },\r\n {\r\n \"@search.action\": \"upload\",\r\n \"hotelId\": \"4\",\r\n \"baseRate\": \"INF\",\r\n \"tags\": []\r\n },\r\n {\r\n \"@search.action\": \"upload\",\r\n \"hotelId\": \"5\",\r\n \"baseRate\": \"NaN\",\r\n \"tags\": []\r\n },\r\n {\r\n \"@search.action\": \"upload\",\r\n \"hotelId\": \"6\",\r\n \"tags\": []\r\n }\r\n ]\r\n}", + "RequestHeaders": { + "Content-Type": [ + "application/json; charset=utf-8" + ], + "Content-Length": [ + "1441" + ], + "accept-language": [ + "en-US" + ], + "Accept": [ + "application/json; odata.metadata=none" + ], + "api-key": [ + "6EEAB44C598F49730C5789F5395F85AB" + ], + "Prefer": [ + "return=representation" + ], + "User-Agent": [ + "FxVersion/4.6.24214.01", + "Microsoft.Azure.Search.SearchIndexClient/3.0.2" + ] + }, + "ResponseBody": "{\"value\":[{\"key\":\"1\",\"status\":true,\"errorMessage\":null,\"statusCode\":201},{\"key\":\"2\",\"status\":true,\"errorMessage\":null,\"statusCode\":201},{\"key\":\"3\",\"status\":true,\"errorMessage\":null,\"statusCode\":201},{\"key\":\"4\",\"status\":true,\"errorMessage\":null,\"statusCode\":201},{\"key\":\"5\",\"status\":true,\"errorMessage\":null,\"statusCode\":201},{\"key\":\"6\",\"status\":true,\"errorMessage\":null,\"statusCode\":201}]}", + "ResponseHeaders": { + "Content-Type": [ + "application/json; odata.metadata=none" + ], + "Expires": [ + "-1" + ], + "Cache-Control": [ + "no-cache" + ], + "Date": [ + "Thu, 23 Feb 2017 03:50:51 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Vary": [ + "Accept-Encoding" + ], + "request-id": [ + "76df546d-34ec-41d6-a9b0-7bf739cb5442" + ], + "elapsed-time": [ + "433" + ], + "OData-Version": [ + "4.0" + ], + "Preference-Applied": [ + "odata.include-annotations=\"*\"" + ], + "Strict-Transport-Security": [ + "max-age=15724800; includeSubDomains" + ] + }, + "StatusCode": 200 + }, + { + "RequestUri": "/indexes('azsmnet4790')/docs('1')?api-version=2016-09-01&$select=*", + "EncodedRequestUri": "L2luZGV4ZXMoJ2F6c21uZXQ0NzkwJykvZG9jcygnMScpP2FwaS12ZXJzaW9uPTIwMTYtMDktMDEmJHNlbGVjdD0lMkE=", + "RequestMethod": "GET", + "RequestBody": "", + "RequestHeaders": { + "accept-language": [ + "en-US" + ], + "Accept": [ + "application/json; odata.metadata=none" + ], + "api-key": [ + "6EEAB44C598F49730C5789F5395F85AB" + ], + "Prefer": [ + "return=representation" + ], + "User-Agent": [ + "FxVersion/4.6.24214.01", + "Microsoft.Azure.Search.SearchIndexClient/3.0.2" + ] + }, + "ResponseBody": "{\"hotelId\":\"1\",\"baseRate\":-1.7976931348623157E+308,\"description\":null,\"descriptionFr\":null,\"hotelName\":null,\"category\":\"\",\"tags\":[],\"parkingIncluded\":false,\"smokingAllowed\":null,\"lastRenovationDate\":\"0001-01-01T00:00:00Z\",\"rating\":-2147483648,\"location\":{\"type\":\"Point\",\"coordinates\":[-180.0,-90.0],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}}", + "ResponseHeaders": { + "Content-Type": [ + "application/json; odata.metadata=none" + ], + "Expires": [ + "-1" + ], + "Cache-Control": [ + "no-cache" + ], + "Date": [ + "Thu, 23 Feb 2017 03:50:53 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Vary": [ + "Accept-Encoding" + ], + "request-id": [ + "bd3f9940-a8e6-4a6c-bb96-a7595fcded62" + ], + "elapsed-time": [ + "4" + ], + "OData-Version": [ + "4.0" + ], + "Preference-Applied": [ + "odata.include-annotations=\"*\"" + ], + "Strict-Transport-Security": [ + "max-age=15724800; includeSubDomains" + ] + }, + "StatusCode": 200 + }, + { + "RequestUri": "/indexes('azsmnet4790')/docs('2')?api-version=2016-09-01&$select=*", + "EncodedRequestUri": "L2luZGV4ZXMoJ2F6c21uZXQ0NzkwJykvZG9jcygnMicpP2FwaS12ZXJzaW9uPTIwMTYtMDktMDEmJHNlbGVjdD0lMkE=", + "RequestMethod": "GET", + "RequestBody": "", + "RequestHeaders": { + "accept-language": [ + "en-US" + ], + "Accept": [ + "application/json; odata.metadata=none" + ], + "api-key": [ + "6EEAB44C598F49730C5789F5395F85AB" + ], + "Prefer": [ + "return=representation" + ], + "User-Agent": [ + "FxVersion/4.6.24214.01", + "Microsoft.Azure.Search.SearchIndexClient/3.0.2" + ] + }, + "ResponseBody": "{\"hotelId\":\"2\",\"baseRate\":1.7976931348623157E+308,\"description\":null,\"descriptionFr\":null,\"hotelName\":null,\"category\":\"test\",\"tags\":[\"test\"],\"parkingIncluded\":true,\"smokingAllowed\":null,\"lastRenovationDate\":\"9999-12-31T23:59:59.999Z\",\"rating\":2147483647,\"location\":{\"type\":\"Point\",\"coordinates\":[180.0,90.0],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}}", + "ResponseHeaders": { + "Content-Type": [ + "application/json; odata.metadata=none" + ], + "Expires": [ + "-1" + ], + "Cache-Control": [ + "no-cache" + ], + "Date": [ + "Thu, 23 Feb 2017 03:50:53 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Vary": [ + "Accept-Encoding" + ], + "request-id": [ + "26d1612a-7f82-48dc-98e6-08c629509a8c" + ], + "elapsed-time": [ + "6" + ], + "OData-Version": [ + "4.0" + ], + "Preference-Applied": [ + "odata.include-annotations=\"*\"" + ], + "Strict-Transport-Security": [ + "max-age=15724800; includeSubDomains" + ] + }, + "StatusCode": 200 + }, + { + "RequestUri": "/indexes('azsmnet4790')/docs('3')?api-version=2016-09-01&$select=*", + "EncodedRequestUri": "L2luZGV4ZXMoJ2F6c21uZXQ0NzkwJykvZG9jcygnMycpP2FwaS12ZXJzaW9uPTIwMTYtMDktMDEmJHNlbGVjdD0lMkE=", + "RequestMethod": "GET", + "RequestBody": "", + "RequestHeaders": { + "accept-language": [ + "en-US" + ], + "Accept": [ + "application/json; odata.metadata=none" + ], + "api-key": [ + "6EEAB44C598F49730C5789F5395F85AB" + ], + "Prefer": [ + "return=representation" + ], + "User-Agent": [ + "FxVersion/4.6.24214.01", + "Microsoft.Azure.Search.SearchIndexClient/3.0.2" + ] + }, + "ResponseBody": "{\"hotelId\":\"3\",\"baseRate\":\"-INF\",\"description\":null,\"descriptionFr\":null,\"hotelName\":null,\"category\":null,\"tags\":[],\"parkingIncluded\":null,\"smokingAllowed\":null,\"lastRenovationDate\":null,\"rating\":null,\"location\":{\"type\":\"Point\",\"coordinates\":[0.0,0.0],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}}", + "ResponseHeaders": { + "Content-Type": [ + "application/json; odata.metadata=none" + ], + "Expires": [ + "-1" + ], + "Cache-Control": [ + "no-cache" + ], + "Date": [ + "Thu, 23 Feb 2017 03:50:53 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Vary": [ + "Accept-Encoding" + ], + "request-id": [ + "198c8c9e-396e-4f5d-8e61-88322f24a809" + ], + "elapsed-time": [ + "5" + ], + "OData-Version": [ + "4.0" + ], + "Preference-Applied": [ + "odata.include-annotations=\"*\"" + ], + "Strict-Transport-Security": [ + "max-age=15724800; includeSubDomains" + ] + }, + "StatusCode": 200 + }, + { + "RequestUri": "/indexes('azsmnet4790')/docs('4')?api-version=2016-09-01&$select=*", + "EncodedRequestUri": "L2luZGV4ZXMoJ2F6c21uZXQ0NzkwJykvZG9jcygnNCcpP2FwaS12ZXJzaW9uPTIwMTYtMDktMDEmJHNlbGVjdD0lMkE=", + "RequestMethod": "GET", + "RequestBody": "", + "RequestHeaders": { + "accept-language": [ + "en-US" + ], + "Accept": [ + "application/json; odata.metadata=none" + ], + "api-key": [ + "6EEAB44C598F49730C5789F5395F85AB" + ], + "Prefer": [ + "return=representation" + ], + "User-Agent": [ + "FxVersion/4.6.24214.01", + "Microsoft.Azure.Search.SearchIndexClient/3.0.2" + ] + }, + "ResponseBody": "{\"hotelId\":\"4\",\"baseRate\":\"INF\",\"description\":null,\"descriptionFr\":null,\"hotelName\":null,\"category\":null,\"tags\":[],\"parkingIncluded\":null,\"smokingAllowed\":null,\"lastRenovationDate\":null,\"rating\":null,\"location\":null}", + "ResponseHeaders": { + "Content-Type": [ + "application/json; odata.metadata=none" + ], + "Expires": [ + "-1" + ], + "Cache-Control": [ + "no-cache" + ], + "Date": [ + "Thu, 23 Feb 2017 03:50:53 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Vary": [ + "Accept-Encoding" + ], + "request-id": [ + "eeeb9b55-a3ef-4727-86ce-c3c0913b0ddc" + ], + "elapsed-time": [ + "3" + ], + "OData-Version": [ + "4.0" + ], + "Preference-Applied": [ + "odata.include-annotations=\"*\"" + ], + "Strict-Transport-Security": [ + "max-age=15724800; includeSubDomains" + ] + }, + "StatusCode": 200 + }, + { + "RequestUri": "/indexes('azsmnet4790')/docs('5')?api-version=2016-09-01&$select=*", + "EncodedRequestUri": "L2luZGV4ZXMoJ2F6c21uZXQ0NzkwJykvZG9jcygnNScpP2FwaS12ZXJzaW9uPTIwMTYtMDktMDEmJHNlbGVjdD0lMkE=", + "RequestMethod": "GET", + "RequestBody": "", + "RequestHeaders": { + "accept-language": [ + "en-US" + ], + "Accept": [ + "application/json; odata.metadata=none" + ], + "api-key": [ + "6EEAB44C598F49730C5789F5395F85AB" + ], + "Prefer": [ + "return=representation" + ], + "User-Agent": [ + "FxVersion/4.6.24214.01", + "Microsoft.Azure.Search.SearchIndexClient/3.0.2" + ] + }, + "ResponseBody": "{\"hotelId\":\"5\",\"baseRate\":\"NaN\",\"description\":null,\"descriptionFr\":null,\"hotelName\":null,\"category\":null,\"tags\":[],\"parkingIncluded\":null,\"smokingAllowed\":null,\"lastRenovationDate\":null,\"rating\":null,\"location\":null}", + "ResponseHeaders": { + "Content-Type": [ + "application/json; odata.metadata=none" + ], + "Expires": [ + "-1" + ], + "Cache-Control": [ + "no-cache" + ], + "Date": [ + "Thu, 23 Feb 2017 03:50:53 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Vary": [ + "Accept-Encoding" + ], + "request-id": [ + "ef254b4d-f4d2-46f2-99d9-53b5a99d4a33" + ], + "elapsed-time": [ + "4" + ], + "OData-Version": [ + "4.0" + ], + "Preference-Applied": [ + "odata.include-annotations=\"*\"" + ], + "Strict-Transport-Security": [ + "max-age=15724800; includeSubDomains" + ] + }, + "StatusCode": 200 + }, + { + "RequestUri": "/indexes('azsmnet4790')/docs('6')?api-version=2016-09-01&$select=*", + "EncodedRequestUri": "L2luZGV4ZXMoJ2F6c21uZXQ0NzkwJykvZG9jcygnNicpP2FwaS12ZXJzaW9uPTIwMTYtMDktMDEmJHNlbGVjdD0lMkE=", + "RequestMethod": "GET", + "RequestBody": "", + "RequestHeaders": { + "accept-language": [ + "en-US" + ], + "Accept": [ + "application/json; odata.metadata=none" + ], + "api-key": [ + "6EEAB44C598F49730C5789F5395F85AB" + ], + "Prefer": [ + "return=representation" + ], + "User-Agent": [ + "FxVersion/4.6.24214.01", + "Microsoft.Azure.Search.SearchIndexClient/3.0.2" + ] + }, + "ResponseBody": "{\"hotelId\":\"6\",\"baseRate\":null,\"description\":null,\"descriptionFr\":null,\"hotelName\":null,\"category\":null,\"tags\":[],\"parkingIncluded\":null,\"smokingAllowed\":null,\"lastRenovationDate\":null,\"rating\":null,\"location\":null}", + "ResponseHeaders": { + "Content-Type": [ + "application/json; odata.metadata=none" + ], + "Expires": [ + "-1" + ], + "Cache-Control": [ + "no-cache" + ], + "Date": [ + "Thu, 23 Feb 2017 03:50:53 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Vary": [ + "Accept-Encoding" + ], + "request-id": [ + "2ce3ab21-51d2-4180-9b3b-e89966cd9446" + ], + "elapsed-time": [ + "4" + ], + "OData-Version": [ + "4.0" + ], + "Preference-Applied": [ + "odata.include-annotations=\"*\"" + ], + "Strict-Transport-Security": [ + "max-age=15724800; includeSubDomains" + ] + }, + "StatusCode": 200 + }, + { + "RequestUri": "/subscriptions/b80cf239-2c72-47ab-b309-b26aec4656b1/resourceGroups/azsmnet5916/providers/Microsoft.Search/searchServices/azs-6259?api-version=2015-08-19", + "EncodedRequestUri": "L3N1YnNjcmlwdGlvbnMvYjgwY2YyMzktMmM3Mi00N2FiLWIzMDktYjI2YWVjNDY1NmIxL3Jlc291cmNlR3JvdXBzL2F6c21uZXQ1OTE2L3Byb3ZpZGVycy9NaWNyb3NvZnQuU2VhcmNoL3NlYXJjaFNlcnZpY2VzL2F6cy02MjU5P2FwaS12ZXJzaW9uPTIwMTUtMDgtMTk=", + "RequestMethod": "DELETE", + "RequestBody": "", + "RequestHeaders": { + "x-ms-client-request-id": [ + "d3dce469-2c08-4d76-be70-19f46fd85783" + ], + "accept-language": [ + "en-US" + ], + "User-Agent": [ + "FxVersion/4.6.24214.01", + "Microsoft.Azure.Management.Search.SearchManagementClient/1.0.1" + ] + }, + "ResponseBody": "", + "ResponseHeaders": { + "Content-Length": [ + "0" + ], + "Expires": [ + "-1" + ], + "Cache-Control": [ + "no-cache" + ], + "Date": [ + "Thu, 23 Feb 2017 03:50:53 GMT" + ], + "Pragma": [ + "no-cache" + ], + "x-ms-request-id": [ + "d3dce469-2c08-4d76-be70-19f46fd85783" + ], + "request-id": [ + "d3dce469-2c08-4d76-be70-19f46fd85783" + ], + "elapsed-time": [ + "417" + ], + "Strict-Transport-Security": [ + "max-age=31536000; includeSubDomains" + ], + "X-AspNet-Version": [ + "4.0.30319" + ], + "x-ms-ratelimit-remaining-subscription-writes": [ + "1183" + ], + "x-ms-correlation-request-id": [ + "d445d646-e4b0-4dcc-ae57-23262f49caa9" + ], + "x-ms-routing-request-id": [ + "CENTRALUS:20170223T035054Z:d445d646-e4b0-4dcc-ae57-23262f49caa9" + ] + }, + "StatusCode": 200 + } + ], + "Names": { + "GenerateName": [ + "azsmnet5916", + "azsmnet4790" + ], + "GenerateServiceName": [ + "azs-6259" + ] + }, + "Variables": { + "SubscriptionId": "b80cf239-2c72-47ab-b309-b26aec4656b1" + } +} \ No newline at end of file diff --git a/src/Search/Search.Tests/Tests/IndexingTests.cs b/src/Search/Search.Tests/Tests/IndexingTests.cs index 7862466076ac..f88d92bcae29 100644 --- a/src/Search/Search.Tests/Tests/IndexingTests.cs +++ b/src/Search/Search.Tests/Tests/IndexingTests.cs @@ -785,6 +785,89 @@ public void CanUseIndexWithReservedName() }); } + [Fact] + public void CanRoundtripBoundaryValues() + { + Run(() => + { + SearchIndexClient client = Data.GetSearchIndexClient(); + + var expectedDocs = new[] + { + // Minimum values + new Hotel() + { + HotelId = "1", + BaseRate = Double.MinValue, + Category = String.Empty, + LastRenovationDate = DateTimeOffset.MinValue, + Location = GeographyPoint.Create(-90, -180), // South pole, date line from the west + ParkingIncluded = false, + Rating = Int32.MinValue, + Tags = new string[0] + }, + // Maximimum values + new Hotel() + { + HotelId = "2", + BaseRate = Double.MaxValue, + Category = "test", // No meaningful string max since there is no length limit (other than payload size or term length). + LastRenovationDate = DateTimeOffset.MaxValue, + Location = GeographyPoint.Create(90, 180), // North pole, date line from the east + ParkingIncluded = true, + Rating = Int32.MaxValue, + Tags = new string[] { "test" } // No meaningful string max; see above. + }, + // Other boundary values #1 + new Hotel() + { + HotelId = "3", + BaseRate = Double.NegativeInfinity, + Category = null, + LastRenovationDate = null, + Location = GeographyPoint.Create(0, 0), // Equator, meridian + ParkingIncluded = null, + Rating = null, + Tags = new string[0] + }, + // Other boundary values #2 + new Hotel() + { + HotelId = "4", + BaseRate = Double.PositiveInfinity, + Location = null, + Tags = new string[0] + }, + // Other boundary values #3 + new Hotel() + { + HotelId = "5", + BaseRate = Double.NaN, + Tags = new string[0] + }, + // Other boundary values #4 + new Hotel() + { + HotelId = "6", + BaseRate = null, + Tags = new string[0] + } + }; + + var batch = IndexBatch.Upload(expectedDocs); + + client.Documents.Index(batch); + + SearchTestUtilities.WaitForIndexing(); + + Hotel[] actualDocs = expectedDocs.Select(d => client.Documents.Get(d.HotelId)).ToArray(); + for (int i = 0; i < actualDocs.Length; i++) + { + Assert.Equal(expectedDocs[i], actualDocs[i]); + } + }); + } + private void TestCanIndexAndRetrieveWithCustomConverter(Action customizeSettings = null) where T : CustomBook, new() { diff --git a/src/Search/Search.Tests/Tests/Models/Hotel.cs b/src/Search/Search.Tests/Tests/Models/Hotel.cs index dac1c2ad8250..365cad715c10 100644 --- a/src/Search/Search.Tests/Tests/Models/Hotel.cs +++ b/src/Search/Search.Tests/Tests/Models/Hotel.cs @@ -48,7 +48,7 @@ public override bool Equals(object obj) return this.HotelId == other.HotelId && - this.BaseRate == other.BaseRate && + DoublesEqual(this.BaseRate, other.BaseRate) && this.Description == other.Description && this.DescriptionFr == other.DescriptionFr && this.HotelName == other.HotelName && @@ -56,7 +56,7 @@ public override bool Equals(object obj) ((this.Tags == null) ? (other.Tags == null || other.Tags.Length == 0) : this.Tags.SequenceEqual(other.Tags ?? new string[0])) && this.ParkingIncluded == other.ParkingIncluded && this.SmokingAllowed == other.SmokingAllowed && - this.LastRenovationDate == other.LastRenovationDate && + DateTimeOffsetsEqual(this.LastRenovationDate, other.LastRenovationDate) && this.Rating == other.Rating && ((this.Location == null) ? other.Location == null : this.Location.Equals(other.Location)); } @@ -108,5 +108,44 @@ public Document AsDocument() { "tags", this.Tags ?? new string[0] } // OData always gives [] instead of null for collections. }; } + + private static bool DoublesEqual(double? x, double? y) + { + if (x == null) + { + return y == null; + } + + if (Double.IsNaN(x.Value)) + { + return y != null && Double.IsNaN(y.Value); + } + + return x == y; + } + + private static bool DateTimeOffsetsEqual(DateTimeOffset? a, DateTimeOffset? b) + { + if (a == null) + { + return b == null; + } + + if (b == null) + { + return false; + } + + if (a.Value.EqualsExact(b.Value)) + { + return true; + } + + // Allow for some loss of precision in the tick count. + long aTicks = a.Value.UtcTicks; + long bTicks = b.Value.UtcTicks; + + return (aTicks / 10000) == (bTicks / 10000); + } } } diff --git a/src/Search/Search.Tests/Tests/Serialization/DocumentConverterTests.cs b/src/Search/Search.Tests/Tests/Serialization/DocumentConverterTests.cs index 45c832d8ea35..14f4258d38c2 100644 --- a/src/Search/Search.Tests/Tests/Serialization/DocumentConverterTests.cs +++ b/src/Search/Search.Tests/Tests/Serialization/DocumentConverterTests.cs @@ -21,7 +21,16 @@ public sealed class DocumentConverterTests private readonly JsonSerializerSettings _settings = new JsonSerializerSettings() { - Converters = new JsonConverter[] { new DocumentConverter(), new GeographyPointConverter(), new DateTimeConverter() }, + Converters = + new JsonConverter[] + { + new DocumentConverter(), + new GeographyPointConverter(), + new DateTimeConverter(), + // DoubleConverter shouldn't make a difference since it only kicks in when deserializing NaN/INF/-INF, and that case + // is currently not covered by DocumentConverter. However, including it for completeness anyway. + new DoubleConverter() + }, DateParseHandling = DateParseHandling.DateTimeOffset, NullValueHandling = NullValueHandling.Include }; @@ -108,16 +117,16 @@ public void SpecialDoublesAreReadAsStrings() const string Json = @"{ ""field1"": ""NaN"", - ""field2"": ""Infinity"", - ""field3"": ""-Infinity"" + ""field2"": ""INF"", + ""field3"": ""-INF"" }"; Document doc = JsonConvert.DeserializeObject(Json, _settings); Assert.Equal(3, doc.Count); Assert.Equal("NaN", doc["field1"]); - Assert.Equal("Infinity", doc["field2"]); - Assert.Equal("-Infinity", doc["field3"]); + Assert.Equal("INF", doc["field2"]); + Assert.Equal("-INF", doc["field3"]); } // This is a pinning test. It is not ideal behavior, but it's the best we can do without type information. diff --git a/src/Search/Search.Tests/Tests/Serialization/DoubleConverterTests.cs b/src/Search/Search.Tests/Tests/Serialization/DoubleConverterTests.cs new file mode 100644 index 000000000000..b3da9406d68f --- /dev/null +++ b/src/Search/Search.Tests/Tests/Serialization/DoubleConverterTests.cs @@ -0,0 +1,124 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for +// license information. + +namespace Microsoft.Azure.Search.Tests +{ + using System; + using System.Collections.Generic; + using System.IO; + using Microsoft.Azure.Search.Serialization; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + using Xunit; + + public sealed class DoubleConverterTests + { + private readonly JsonSerializerSettings _serializerSettings = + new JsonSerializerSettings() { Converters = new List() { new DoubleConverter() } }; + + private readonly JsonSerializerSettings _deserializerSettings = + new JsonSerializerSettings() { Converters = new List() { new DoubleConverter() } }; + + private readonly Tuple[] _writeTestCases = + new[] + { + Tuple.Create(3.14d, "3.14"), + Tuple.Create(123d, "123.0"), + Tuple.Create(0d, "0.0"), + Tuple.Create(0.0d, "0.0"), + Tuple.Create(1.0d, "1.0"), + Tuple.Create(Double.NegativeInfinity, @"""-INF"""), + Tuple.Create(Double.PositiveInfinity, @"""INF"""), + Tuple.Create(Double.NaN, @"""NaN"""), + Tuple.Create(Double.MinValue, "-1.7976931348623157E+308"), + Tuple.Create(Double.MaxValue, "1.7976931348623157E+308") + }; + + private readonly Tuple[] _readTestCases = + new[] + { + Tuple.Create(3.14d, "3.14"), + Tuple.Create(123d, "123"), + Tuple.Create(0d, "0"), + Tuple.Create(0.0d, "0"), + Tuple.Create(1.0d, "1"), + Tuple.Create(Double.NegativeInfinity, @"""-INF"""), + Tuple.Create(Double.PositiveInfinity, @"""INF"""), + Tuple.Create(Double.NaN, @"""NaN"""), + Tuple.Create(Double.MinValue, "-1.7976931348623157E+308"), + Tuple.Create(Double.MaxValue, "1.7976931348623157E+308") + }; + + [Fact] + public void CanWriteDoubleValues() + { + foreach (var testCase in _writeTestCases) + { + double doubleValue = testCase.Item1; + string expectedJson = testCase.Item2; + + string json = JsonConvert.SerializeObject(doubleValue, _serializerSettings); + Assert.Equal(expectedJson, json); + } + } + + [Fact] + public void CanWriteNullableDouble() + { + double? nullableDouble = 3.14159; + + // Due to some JSON.NET weirdness, we need to wrap it in an object to trigger the double? detection path. + object obj = new { PI = nullableDouble }; + string json = JsonConvert.SerializeObject(obj, _serializerSettings); + Assert.Equal(@"{""PI"":3.14159}", json); + } + + [Fact] + public void CanReadDoubleValues() + { + foreach (var testCase in _readTestCases) + { + double expectedDoubleValue = testCase.Item1; + string json = testCase.Item2; + + double actualDoubleValue = JsonConvert.DeserializeObject(json, _deserializerSettings); + Assert.Equal(expectedDoubleValue, actualDoubleValue); + } + } + + [Fact] + public void CanReadNullableDouble() + { + double? expectedDouble = 3.14159; + double? actualDouble = JsonConvert.DeserializeObject("3.14159", _deserializerSettings); + Assert.Equal(expectedDouble, actualDouble); + } + + [Fact] + public void CanReadNullDouble() + { + double? nullDouble = null; + double? actualDouble = JsonConvert.DeserializeObject("null", _deserializerSettings); + Assert.Equal(nullDouble, actualDouble); + } + + [Fact] + public void CanReadPreParsedDouble() + { + const string Json = @"{""Price"":""3.50""}"; + using (JsonReader reader = new JsonTextReader(new StringReader(Json))) + { + JsonSerializer serializer = JsonSerializer.Create(_deserializerSettings); + JObject propertyBag = serializer.Deserialize(reader); + Model model = serializer.Deserialize(new JTokenReader(propertyBag)); + Assert.Equal(3.5, model.Price); + } + } + + private class Model + { + public double Price { get; set; } + } + } +}