Integrating master direct pacakge [BREAKING CHANGES] (#97)
* a draft version * One more draft * Simple namespace and code removal changes * New REST contract types * Some more contract changes * Moving type conversion to new CosmosResource * Some more contract changes * Dance between different resource types * Committing a binary diff * Test project changes * Cosmos tests building * Tests green * CosmosResource as base type removed and required properties are in-lined AltLink is removed from all resources and also consumption constructs them on-demand. * Committing local project system changes as well. * New contract validation tests for database and container to match old contracts Leveraged C# 6.0 syntax to clean-up default initialization code PartitionKeyRangeStatisc type removed from contracts Future work: 1. SchemaBuilderPolicy 2. SpatialSpec 3. CompositePaths * RequestOptions excluded from GitHub Mainfest bug fix (all UT GREEN now) * Some more emulator cmpilation fixes * Emulator project building * Integrated into new StoreClientFactory * Some more test fixes * All except performance GREEN * Including missing file * Ignoring all quarantines tests * All emulator tests GREEN * All solution GREEN * Including JsonNavigator code Also all solution builds GREEN * Cosmos regions & Proximity utils moved to Direct. Offer tests fixed. * Moving UT into unit-tests project. * Removing TestJosns from Test FX project * Solition and project file changes refresh
This commit is contained in:
Родитель
175a52286d
Коммит
5ce792f507
|
@ -27,7 +27,6 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// </example>
|
||||
/// <seealso cref="AccessConditionType"/>
|
||||
/// <seealso cref="RequestOptions"/>
|
||||
/// <seealso cref="CosmosResource"/>
|
||||
public sealed class AccessCondition
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -44,7 +43,6 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// <value>
|
||||
/// The value of the condition. For <see cref="AccessConditionType"/> IfMatch and IfNotMatch, this is the ETag that has to be compared to.
|
||||
/// </value>
|
||||
/// <seealso cref="CosmosResource"/>
|
||||
public string Condition { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
#if !SignAssembly
|
||||
[assembly: InternalsVisibleTo("Microsoft.Azure.Cosmos.Tests")]
|
||||
[assembly: InternalsVisibleTo("Microsoft.Azure.Cosmos.EmulatorTests")]
|
||||
[assembly: InternalsVisibleTo("Microsoft.Azure.Cosmos.Friends.Tests")]
|
||||
|
@ -14,26 +13,3 @@ using System.Runtime.CompilerServices;
|
|||
[assembly: InternalsVisibleTo("Microsoft.Azure.Cosmos.NetFramework.Tests")]
|
||||
[assembly: InternalsVisibleTo("Microsoft.Azure.Cosmos.Performance.Tests")]
|
||||
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
|
||||
#endif
|
||||
|
||||
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2" + AssemblyRef.MoqPublicKey)]
|
||||
[assembly: InternalsVisibleTo("Microsoft.Azure.Cosmos.Tests" + AssemblyRef.ProductPublicKey)]
|
||||
[assembly: InternalsVisibleTo("Microsoft.Azure.Cosmos.EmulatorTests" + AssemblyRef.ProductPublicKey)]
|
||||
[assembly: InternalsVisibleTo("Microsoft.Azure.Cosmos.Friends.Tests" + AssemblyRef.ProductPublicKey)]
|
||||
[assembly: InternalsVisibleTo("Microsoft.Azure.Cosmos.Friends" + AssemblyRef.ProductPublicKey)]
|
||||
[assembly: InternalsVisibleTo("Microsoft.Azure.Cosmos.Extensions.Tests" + AssemblyRef.ProductPublicKey)]
|
||||
[assembly: InternalsVisibleTo("Microsoft.Azure.Cosmos.Extensions" + AssemblyRef.ProductPublicKey)]
|
||||
[assembly: InternalsVisibleTo("Microsoft.Azure.Cosmos.NetFramework.Tests" + AssemblyRef.ProductPublicKey)]
|
||||
[assembly: InternalsVisibleTo("Microsoft.Azure.Cosmos.Tests" + AssemblyRef.TestPublicKey)]
|
||||
[assembly: InternalsVisibleTo("Microsoft.Azure.Cosmos.EmulatorTests" + AssemblyRef.TestPublicKey)]
|
||||
[assembly: InternalsVisibleTo("Microsoft.Azure.Cosmos.Friends.Tests" + AssemblyRef.TestPublicKey)]
|
||||
[assembly: InternalsVisibleTo("Microsoft.Azure.Cosmos.Friends" + AssemblyRef.TestPublicKey)]
|
||||
[assembly: InternalsVisibleTo("Microsoft.Azure.Cosmos.Extensions.Tests" + AssemblyRef.TestPublicKey)]
|
||||
[assembly: InternalsVisibleTo("Microsoft.Azure.Cosmos.Extensions" + AssemblyRef.TestPublicKey)]
|
||||
[assembly: InternalsVisibleTo("Microsoft.Azure.Cosmos.NetFramework.Tests" + AssemblyRef.TestPublicKey)]
|
||||
[assembly: InternalsVisibleTo("Microsoft.Azure.Cosmos.Table" + AssemblyRef.ProductPublicKey)]
|
||||
[assembly: InternalsVisibleTo("Microsoft.Azure.Cosmos.Table" + AssemblyRef.TestPublicKey)]
|
||||
[assembly: InternalsVisibleTo("Microsoft.Azure.Cosmos.Table.Tests" + AssemblyRef.ProductPublicKey)]
|
||||
[assembly: InternalsVisibleTo("Microsoft.Azure.Cosmos.Table.Tests" + AssemblyRef.TestPublicKey)]
|
||||
[assembly: InternalsVisibleTo("Microsoft.Azure.Cosmos.Performance.Tests" + AssemblyRef.ProductPublicKey)]
|
||||
[assembly: InternalsVisibleTo("Microsoft.Azure.Cosmos.Performance.Tests" + AssemblyRef.TestPublicKey)]
|
||||
|
|
|
@ -5,6 +5,8 @@ namespace Microsoft.Azure.Cosmos
|
|||
{
|
||||
using Microsoft.Azure.Cosmos.Collections;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Documents;
|
||||
using Microsoft.Azure.Documents.Collections;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
|
|
|
@ -9,6 +9,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Documents;
|
||||
|
||||
internal static class Base64Helper
|
||||
{
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
namespace Microsoft.Azure.Cosmos
|
||||
{
|
||||
using System;
|
||||
using Microsoft.Azure.Documents;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the options associated with change feed methods (enumeration operations) in the Azure Cosmos DB service.
|
||||
|
|
|
@ -13,6 +13,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Cosmos.Routing;
|
||||
using Microsoft.Azure.Documents;
|
||||
|
||||
/// <summary>
|
||||
/// This retry policy is designed to work with in a pair with ClientRetryPolicy.
|
||||
|
|
|
@ -16,6 +16,8 @@ namespace Microsoft.Azure.Cosmos
|
|||
|
||||
#if !NETSTANDARD16
|
||||
using System.Diagnostics;
|
||||
using Microsoft.Azure.Documents.Collections;
|
||||
using Microsoft.Azure.Documents;
|
||||
#endif
|
||||
|
||||
internal static class ClientExtensions
|
||||
|
@ -112,7 +114,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
if (string.Equals(responseMessage.Content?.Headers?.ContentType?.MediaType, ClientExtensions.MediaTypeJson, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Stream readStream = await responseMessage.Content.ReadAsStreamAsync();
|
||||
Error error = CosmosResource.LoadFrom<Error>(readStream);
|
||||
Error error = Resource.LoadFrom<Error>(readStream);
|
||||
return new DocumentClientException(
|
||||
error,
|
||||
responseMessage.Headers,
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
namespace Microsoft.Azure.Cosmos {
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
|
||||
/// <summary>
|
||||
|
@ -39,7 +40,7 @@ namespace Microsoft.Azure.Cosmos {
|
|||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.Azure.Cosmos.ClientResources", typeof(ClientResources).GetAssembly());
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.Azure.Cosmos.ClientResources", typeof(ClientResources).GetTypeInfo().Assembly);
|
||||
|
||||
resourceMan = temp;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@ namespace Microsoft.Azure.Cosmos
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Cosmos.Routing;
|
||||
using Microsoft.Azure.Documents;
|
||||
|
||||
/// <summary>
|
||||
/// Client policy is combination of endpoint change retry + throttling retry.
|
||||
/// </summary>
|
||||
|
|
|
@ -8,6 +8,8 @@ namespace Microsoft.Azure.Cosmos
|
|||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Documents;
|
||||
using Microsoft.Azure.Documents.Client;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the connection policy associated with a DocumentClient to connect to the Azure Cosmos DB service.
|
||||
|
|
|
@ -227,7 +227,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
);
|
||||
|
||||
// DocumentClient is not initialized with any consistency overrides so default is backend consistency
|
||||
this.AccountConsistencyLevel = this.DocumentClient.ConsistencyLevel;
|
||||
this.AccountConsistencyLevel = (ConsistencyLevel)this.DocumentClient.ConsistencyLevel;
|
||||
|
||||
this.RequestHandler = clientPipelineBuilder.Build();
|
||||
this.Databases = new CosmosDatabases(this);
|
||||
|
|
|
@ -8,6 +8,8 @@ namespace Microsoft.Azure.Cosmos
|
|||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Documents;
|
||||
using Microsoft.Azure.Documents.Client;
|
||||
|
||||
/// <summary>
|
||||
/// This is a Builder class that creates a cosmos client
|
||||
|
|
|
@ -9,6 +9,8 @@ namespace Microsoft.Azure.Cosmos
|
|||
using System.Data.Common;
|
||||
using System.Linq;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Documents;
|
||||
using Microsoft.Azure.Documents.Client;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -14,8 +14,11 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// </summary>
|
||||
internal class CosmosDefaultJsonSerializer : CosmosJsonSerializer
|
||||
{
|
||||
private static readonly JsonSerializer Serializer = new JsonSerializer();
|
||||
private static readonly Encoding DefaultEncoding = new UTF8Encoding(false, true);
|
||||
private static readonly JsonSerializer Serializer = new JsonSerializer()
|
||||
{
|
||||
NullValueHandling = NullValueHandling.Ignore,
|
||||
};
|
||||
|
||||
public override T FromStream<T>(Stream stream)
|
||||
{
|
||||
|
|
|
@ -1,266 +0,0 @@
|
|||
//------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------
|
||||
namespace Microsoft.Azure.Cosmos
|
||||
{
|
||||
/// <summary>
|
||||
/// The Azure regions that are currently supported by the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public static class CosmosRegions
|
||||
{
|
||||
/// <summary>
|
||||
/// Name of the Azure West US region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string WestUS = "West US";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure West US 2 region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string WestUS2 = "West US 2";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure West Central US region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string WestCentralUS = "West Central US";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure East US region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string EastUS = "East US";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure East US 2 region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string EastUS2 = "East US 2";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure Central US region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string CentralUS = "Central US";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure Sourth Central US region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string SouthCentralUS = "South Central US";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure North Central US region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string NorthCentralUS = "North Central US";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure West Europe region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string WestEurope = "West Europe";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure North Europe region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string NorthEurope = "North Europe";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure East Asia region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string EastAsia = "East Asia";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure Southeast Asia region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string SoutheastAsia = "Southeast Asia";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure Japan East region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string JapanEast = "Japan East";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure Japan West region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string JapanWest = "Japan West";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure Australia East region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string AustraliaEast = "Australia East";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure Australia Southeast region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string AustraliaSoutheast = "Australia Southeast";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure Central India region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string CentralIndia = "Central India";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure South India region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string SouthIndia = "South India";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure West India region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string WestIndia = "West India";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure Canada East region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string CanadaEast = "Canada East";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure Canada Central region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string CanadaCentral = "Canada Central";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure Germany Central region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string GermanyCentral = "Germany Central";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure Germany Northeast region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string GermanyNortheast = "Germany Northeast";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure China North region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string ChinaNorth = "China North";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure China East region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string ChinaEast = "China East";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure China North 2 region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string ChinaNorth2 = "China North 2";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure China East 2 region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string ChinaEast2 = "China East 2";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure Korea South region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string KoreaSouth = "Korea South";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure Korea Central region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string KoreaCentral = "Korea Central";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure UK West region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string UKWest = "UK West";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure UK South region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string UKSouth = "UK South";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure Brazil South region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string BrazilSouth = "Brazil South";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure USGov Arizona region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string USGovArizona = "USGov Arizona";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure USGov Texas region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string USGovTexas = "USGov Texas";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure USGov Virginia region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string USGovVirginia = "USGov Virginia";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure East US 2 EUAP region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string EastUS2EUAP = "East US 2 EUAP";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure Central US EUAP region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string CentralUSEUAP = "Central US EUAP";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure France Central region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string FranceCentral = "France Central";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure France South region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string FranceSouth = "France South";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure DoD Central region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string USDoDCentral = "USDoD Central";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure DoD East region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string USDoDEast = "USDoD East";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure Australia Central region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string AustraliaCentral = "Australia Central";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure Australia Central 2 region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string AustraliaCentral2 = "Australia Central 2";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure South Africa North region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string SouthAfricaNorth = "South Africa North";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure South Africa West region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string SouthAfricaWest = "South Africa West";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure UAE Central region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string UAECentral = "UAE Central";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure UAE North region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string UAENorth = "UAE North";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure USNat East region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string USNatEast = "USNat East";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure USNat West region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string USNatWest = "USNat West";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure USSec East region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string USSecEast = "USSec East";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Azure USNat West region in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public const string USSecWest = "USSec West";
|
||||
}
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -7,6 +7,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
using System.Diagnostics.Tracing;
|
||||
using System.Net.Http.Headers;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Documents;
|
||||
|
||||
[EventSource(Name = "DocumentDBClient", Guid = "f832a342-0a53-5bab-b57b-d5bc65319768")]
|
||||
// Marking it as non-sealed in order to unit test it using Moq framework
|
||||
|
|
|
@ -11,8 +11,9 @@ namespace Microsoft.Azure.Cosmos
|
|||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Cosmos.Linq;
|
||||
using Microsoft.Azure.Documents;
|
||||
using Microsoft.Azure.Documents.Client;
|
||||
|
||||
internal partial class DocumentClient : IDisposable, IAuthorizationTokenProvider
|
||||
{
|
||||
|
@ -45,7 +46,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// <param name="documentCollection">the Microsoft.Azure.Documents.DocumentCollection object.</param>
|
||||
/// <param name="options">The request options for the request.</param>
|
||||
/// <returns>The task object representing the service response for the asynchronous operation.</returns>
|
||||
public Task<ResourceResponse<CosmosContainerSettings>> CreateDocumentCollectionAsync(Uri databaseUri, CosmosContainerSettings documentCollection, RequestOptions options = null)
|
||||
public Task<ResourceResponse<DocumentCollection>> CreateDocumentCollectionAsync(Uri databaseUri, DocumentCollection documentCollection, RequestOptions options = null)
|
||||
{
|
||||
if (databaseUri == null)
|
||||
{
|
||||
|
@ -58,16 +59,16 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// Creates(if doesn't exist) or gets(if already exists) a collection as an asychronous operation in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <param name="databaseUri">the URI of the database to create the collection in.</param>
|
||||
/// <param name="documentCollection">The <see cref="CosmosContainerSettings"/> object.</param>
|
||||
/// <param name="documentCollection">The <see cref="DocumentCollection"/> object.</param>
|
||||
/// <param name="options">(Optional) Any <see cref="Microsoft.Azure.Cosmos.RequestOptions"/> you wish to provide when creating a Collection. E.g. RequestOptions.OfferThroughput = 400. </param>
|
||||
/// <returns>The <see cref="CosmosContainerSettings"/> that was created contained within a <see cref="System.Threading.Tasks.Task"/> object representing the service response for the asynchronous operation.</returns>
|
||||
public Task<ResourceResponse<CosmosContainerSettings>> CreateDocumentCollectionIfNotExistsAsync(Uri databaseUri, CosmosContainerSettings documentCollection, RequestOptions options = null)
|
||||
/// <returns>The <see cref="DocumentCollection"/> that was created contained within a <see cref="System.Threading.Tasks.Task"/> object representing the service response for the asynchronous operation.</returns>
|
||||
public Task<ResourceResponse<DocumentCollection>> CreateDocumentCollectionIfNotExistsAsync(Uri databaseUri, DocumentCollection documentCollection, RequestOptions options = null)
|
||||
{
|
||||
return TaskHelper.InlineIfPossible(() => CreateDocumentCollectionIfNotExistsPrivateAsync(databaseUri, documentCollection, options), null);
|
||||
}
|
||||
|
||||
private async Task<ResourceResponse<CosmosContainerSettings>> CreateDocumentCollectionIfNotExistsPrivateAsync(
|
||||
Uri databaseUri, CosmosContainerSettings documentCollection, RequestOptions options)
|
||||
private async Task<ResourceResponse<DocumentCollection>> CreateDocumentCollectionIfNotExistsPrivateAsync(
|
||||
Uri databaseUri, DocumentCollection documentCollection, RequestOptions options)
|
||||
{
|
||||
if (databaseUri == null)
|
||||
{
|
||||
|
@ -116,7 +117,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// <param name="storedProcedure">the Microsoft.Azure.Documents.StoredProcedure object.</param>
|
||||
/// <param name="options">The request options for the request.</param>
|
||||
/// <returns>The task object representing the service response for the asynchronous operation.</returns>
|
||||
public Task<ResourceResponse<CosmosStoredProcedureSettings>> CreateStoredProcedureAsync(Uri documentCollectionUri, CosmosStoredProcedureSettings storedProcedure, RequestOptions options = null)
|
||||
public Task<ResourceResponse<StoredProcedure>> CreateStoredProcedureAsync(Uri documentCollectionUri, StoredProcedure storedProcedure, RequestOptions options = null)
|
||||
{
|
||||
if (documentCollectionUri == null)
|
||||
{
|
||||
|
@ -132,7 +133,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// <param name="trigger">the Microsoft.Azure.Documents.Trigger object.</param>
|
||||
/// <param name="options">The request options for the request.</param>
|
||||
/// <returns>The task object representing the service response for the asynchronous operation.</returns>
|
||||
public Task<ResourceResponse<CosmosTriggerSettings>> CreateTriggerAsync(Uri documentCollectionUri, CosmosTriggerSettings trigger, RequestOptions options = null)
|
||||
public Task<ResourceResponse<Trigger>> CreateTriggerAsync(Uri documentCollectionUri, Trigger trigger, RequestOptions options = null)
|
||||
{
|
||||
if (documentCollectionUri == null)
|
||||
{
|
||||
|
@ -148,7 +149,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// <param name="function">the Microsoft.Azure.Documents.UserDefinedFunction object.</param>
|
||||
/// <param name="options">The request options for the request.</param>
|
||||
/// <returns>The task object representing the service response for the asynchronous operation.</returns>
|
||||
public Task<ResourceResponse<CosmosUserDefinedFunctionSettings>> CreateUserDefinedFunctionAsync(Uri documentCollectionUri, CosmosUserDefinedFunctionSettings function, RequestOptions options = null)
|
||||
public Task<ResourceResponse<UserDefinedFunction>> CreateUserDefinedFunctionAsync(Uri documentCollectionUri, UserDefinedFunction function, RequestOptions options = null)
|
||||
{
|
||||
if (documentCollectionUri == null)
|
||||
{
|
||||
|
@ -202,7 +203,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// <param name="storedProcedure">the Microsoft.Azure.Documents.StoredProcedure object.</param>
|
||||
/// <param name="options">The request options for the request.</param>
|
||||
/// <returns>The task object representing the service response for the asynchronous operation.</returns>
|
||||
public Task<ResourceResponse<CosmosStoredProcedureSettings>> UpsertStoredProcedureAsync(Uri documentCollectionUri, CosmosStoredProcedureSettings storedProcedure, RequestOptions options = null)
|
||||
public Task<ResourceResponse<StoredProcedure>> UpsertStoredProcedureAsync(Uri documentCollectionUri, StoredProcedure storedProcedure, RequestOptions options = null)
|
||||
{
|
||||
if (documentCollectionUri == null)
|
||||
{
|
||||
|
@ -218,7 +219,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// <param name="trigger">the Microsoft.Azure.Documents.Trigger object.</param>
|
||||
/// <param name="options">The request options for the request.</param>
|
||||
/// <returns>The task object representing the service response for the asynchronous operation.</returns>
|
||||
public Task<ResourceResponse<CosmosTriggerSettings>> UpsertTriggerAsync(Uri documentCollectionUri, CosmosTriggerSettings trigger, RequestOptions options = null)
|
||||
public Task<ResourceResponse<Trigger>> UpsertTriggerAsync(Uri documentCollectionUri, Trigger trigger, RequestOptions options = null)
|
||||
{
|
||||
if (documentCollectionUri == null)
|
||||
{
|
||||
|
@ -234,7 +235,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// <param name="function">the Microsoft.Azure.Documents.UserDefinedFunction object.</param>
|
||||
/// <param name="options">The request options for the request.</param>
|
||||
/// <returns>The task object representing the service response for the asynchronous operation.</returns>
|
||||
public Task<ResourceResponse<CosmosUserDefinedFunctionSettings>> UpsertUserDefinedFunctionAsync(Uri documentCollectionUri, CosmosUserDefinedFunctionSettings function, RequestOptions options = null)
|
||||
public Task<ResourceResponse<UserDefinedFunction>> UpsertUserDefinedFunctionAsync(Uri documentCollectionUri, UserDefinedFunction function, RequestOptions options = null)
|
||||
{
|
||||
if (documentCollectionUri == null)
|
||||
{
|
||||
|
@ -267,7 +268,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// <param name="databaseUri">the URI of the database to delete.</param>
|
||||
/// <param name="options">The request options for the request.</param>
|
||||
/// <returns>The task object representing the service response for the asynchronous operation.</returns>
|
||||
public Task<ResourceResponse<CosmosDatabaseSettings>> DeleteDatabaseAsync(Uri databaseUri, RequestOptions options = null)
|
||||
public Task<ResourceResponse<Database>> DeleteDatabaseAsync(Uri databaseUri, RequestOptions options = null)
|
||||
{
|
||||
if (databaseUri == null)
|
||||
{
|
||||
|
@ -298,7 +299,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// <param name="documentCollectionUri">the URI of the document collection to delete.</param>
|
||||
/// <param name="options">The request options for the request.</param>
|
||||
/// <returns>The task object representing the service response for the asynchronous operation.</returns>
|
||||
public Task<ResourceResponse<CosmosContainerSettings>> DeleteDocumentCollectionAsync(Uri documentCollectionUri, RequestOptions options = null)
|
||||
public Task<ResourceResponse<DocumentCollection>> DeleteDocumentCollectionAsync(Uri documentCollectionUri, RequestOptions options = null)
|
||||
{
|
||||
if (documentCollectionUri == null)
|
||||
{
|
||||
|
@ -313,7 +314,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// <param name="storedProcedureUri">the URI of the stored procedure to delete.</param>
|
||||
/// <param name="options">The request options for the request.</param>
|
||||
/// <returns>The task object representing the service response for the asynchronous operation.</returns>
|
||||
public Task<ResourceResponse<CosmosStoredProcedureSettings>> DeleteStoredProcedureAsync(Uri storedProcedureUri, RequestOptions options = null)
|
||||
public Task<ResourceResponse<StoredProcedure>> DeleteStoredProcedureAsync(Uri storedProcedureUri, RequestOptions options = null)
|
||||
{
|
||||
if (storedProcedureUri == null)
|
||||
{
|
||||
|
@ -329,7 +330,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// <param name="triggerUri">the URI of the trigger to delete.</param>
|
||||
/// <param name="options">The request options for the request.</param>
|
||||
/// <returns>The task object representing the service response for the asynchronous operation.</returns>
|
||||
public Task<ResourceResponse<CosmosTriggerSettings>> DeleteTriggerAsync(Uri triggerUri, RequestOptions options = null)
|
||||
public Task<ResourceResponse<Trigger>> DeleteTriggerAsync(Uri triggerUri, RequestOptions options = null)
|
||||
{
|
||||
if (triggerUri == null)
|
||||
{
|
||||
|
@ -344,7 +345,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// <param name="functionUri">the URI of the user defined function to delete.</param>
|
||||
/// <param name="options">The request options for the request.</param>
|
||||
/// <returns>The task object representing the service response for the asynchronous operation.</returns>
|
||||
public Task<ResourceResponse<CosmosUserDefinedFunctionSettings>> DeleteUserDefinedFunctionAsync(Uri functionUri, RequestOptions options = null)
|
||||
public Task<ResourceResponse<UserDefinedFunction>> DeleteUserDefinedFunctionAsync(Uri functionUri, RequestOptions options = null)
|
||||
{
|
||||
if (functionUri == null)
|
||||
{
|
||||
|
@ -394,7 +395,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// <param name="documentCollection">the updated document collection.</param>
|
||||
/// <param name="options">The request options for the request.</param>
|
||||
/// <returns>The task object representing the service response for the asynchronous operation.</returns>
|
||||
public Task<ResourceResponse<CosmosContainerSettings>> ReplaceDocumentCollectionAsync(Uri documentCollectionUri, CosmosContainerSettings documentCollection, RequestOptions options = null)
|
||||
public Task<ResourceResponse<DocumentCollection>> ReplaceDocumentCollectionAsync(Uri documentCollectionUri, DocumentCollection documentCollection, RequestOptions options = null)
|
||||
{
|
||||
if (documentCollectionUri == null)
|
||||
{
|
||||
|
@ -416,7 +417,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// <param name="storedProcedure">the updated stored procedure.</param>
|
||||
/// <param name="options">The request options for the request.</param>
|
||||
/// <returns>The task object representing the service response for the asynchronous operation.</returns>
|
||||
public Task<ResourceResponse<CosmosStoredProcedureSettings>> ReplaceStoredProcedureAsync(Uri storedProcedureUri, CosmosStoredProcedureSettings storedProcedure, RequestOptions options = null)
|
||||
public Task<ResourceResponse<StoredProcedure>> ReplaceStoredProcedureAsync(Uri storedProcedureUri, StoredProcedure storedProcedure, RequestOptions options = null)
|
||||
{
|
||||
if (storedProcedureUri == null)
|
||||
{
|
||||
|
@ -438,7 +439,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// <param name="trigger">the updated trigger.</param>
|
||||
/// <param name="options">The request options for the request.</param>
|
||||
/// <returns>The task object representing the service response for the asynchronous operation.</returns>
|
||||
public Task<ResourceResponse<CosmosTriggerSettings>> ReplaceTriggerAsync(Uri triggerUri, CosmosTriggerSettings trigger, RequestOptions options = null)
|
||||
public Task<ResourceResponse<Trigger>> ReplaceTriggerAsync(Uri triggerUri, Trigger trigger, RequestOptions options = null)
|
||||
{
|
||||
if (triggerUri == null)
|
||||
{
|
||||
|
@ -456,7 +457,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// <param name="function">the updated user defined function.</param>
|
||||
/// <param name="options">The request options for the request.</param>
|
||||
/// <returns>The task object representing the service response for the asynchronous operation.</returns>
|
||||
public Task<ResourceResponse<CosmosUserDefinedFunctionSettings>> ReplaceUserDefinedFunctionAsync(Uri userDefinedFunctionUri, CosmosUserDefinedFunctionSettings function, RequestOptions options = null)
|
||||
public Task<ResourceResponse<UserDefinedFunction>> ReplaceUserDefinedFunctionAsync(Uri userDefinedFunctionUri, UserDefinedFunction function, RequestOptions options = null)
|
||||
{
|
||||
if (userDefinedFunctionUri == null)
|
||||
{
|
||||
|
@ -488,12 +489,12 @@ namespace Microsoft.Azure.Cosmos
|
|||
|
||||
#region Read operation
|
||||
/// <summary>
|
||||
/// Reads a <see cref="CosmosDatabaseSettings"/> as an asynchronous operation from the Azure Cosmos DB service.
|
||||
/// Reads a <see cref="Database"/> as an asynchronous operation from the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <param name="databaseUri">A URI to the Database resource to be read.</param>
|
||||
/// <param name="options">The request options for the request.</param>
|
||||
/// <returns>
|
||||
/// A <see cref="System.Threading.Tasks"/> containing a <see cref="Microsoft.Azure.Cosmos.ResourceResponse{T}"/> which wraps a <see cref="CosmosDatabaseSettings"/> containing the read resource record.
|
||||
/// A <see cref="System.Threading.Tasks"/> containing a <see cref="Microsoft.Azure.Cosmos.ResourceResponse{T}"/> which wraps a <see cref="Database"/> containing the read resource record.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">If <paramref name="databaseUri"/> is not set.</exception>
|
||||
/// <exception cref="DocumentClientException">This exception can encapsulate many different types of errors. To determine the specific error always look at the StatusCode property. Some common codes you may get when creating a Document are:
|
||||
|
@ -524,11 +525,11 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// Doing a read of a resource is the most efficient way to get a resource from the service. If you know the resource's ID, do a read instead of a query by ID.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <seealso cref="CosmosDatabaseSettings"/>
|
||||
/// <seealso cref="Database"/>
|
||||
/// <seealso cref="Microsoft.Azure.Cosmos.RequestOptions"/>
|
||||
/// <seealso cref="Microsoft.Azure.Cosmos.ResourceResponse{T}"/>
|
||||
/// <seealso cref="System.Threading.Tasks.Task"/>
|
||||
public Task<ResourceResponse<CosmosDatabaseSettings>> ReadDatabaseAsync(Uri databaseUri, RequestOptions options = null)
|
||||
public Task<ResourceResponse<Database>> ReadDatabaseAsync(Uri databaseUri, RequestOptions options = null)
|
||||
{
|
||||
if (databaseUri == null)
|
||||
{
|
||||
|
@ -644,12 +645,12 @@ namespace Microsoft.Azure.Cosmos
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a <see cref="CosmosContainerSettings"/> as an asynchronous operation from the Azure Cosmos DB service.
|
||||
/// Reads a <see cref="DocumentCollection"/> as an asynchronous operation from the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <param name="documentCollectionUri">A URI to the DocumentCollection resource to be read.</param>
|
||||
/// <param name="options">The request options for the request.</param>
|
||||
/// <returns>
|
||||
/// A <see cref="System.Threading.Tasks"/> containing a <see cref="Microsoft.Azure.Cosmos.ResourceResponse{T}"/> which wraps a <see cref="CosmosContainerSettings"/> containing the read resource record.
|
||||
/// A <see cref="System.Threading.Tasks"/> containing a <see cref="Microsoft.Azure.Cosmos.ResourceResponse{T}"/> which wraps a <see cref="DocumentCollection"/> containing the read resource record.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">If <paramref name="documentCollectionUri"/> is not set.</exception>
|
||||
/// <exception cref="DocumentClientException">This exception can encapsulate many different types of errors. To determine the specific error always look at the StatusCode property. Some common codes you may get when creating a Document are:
|
||||
|
@ -681,11 +682,11 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// Doing a read of a resource is the most efficient way to get a resource from the service. If you know the resource's ID, do a read instead of a query by ID.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <seealso cref="CosmosContainerSettings"/>
|
||||
/// <seealso cref="DocumentCollection"/>
|
||||
/// <seealso cref="Microsoft.Azure.Cosmos.RequestOptions"/>
|
||||
/// <seealso cref="Microsoft.Azure.Cosmos.ResourceResponse{T}"/>
|
||||
/// <seealso cref="System.Threading.Tasks.Task"/>
|
||||
public Task<ResourceResponse<CosmosContainerSettings>> ReadDocumentCollectionAsync(Uri documentCollectionUri, RequestOptions options = null)
|
||||
public Task<ResourceResponse<DocumentCollection>> ReadDocumentCollectionAsync(Uri documentCollectionUri, RequestOptions options = null)
|
||||
{
|
||||
if (documentCollectionUri == null)
|
||||
{
|
||||
|
@ -695,12 +696,12 @@ namespace Microsoft.Azure.Cosmos
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a <see cref="CosmosStoredProcedureSettings"/> as an asynchronous operation from the Azure Cosmos DB service.
|
||||
/// Reads a <see cref="StoredProcedure"/> as an asynchronous operation from the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <param name="storedProcedureUri">A URI to the StoredProcedure resource to be read.</param>
|
||||
/// <param name="options">The request options for the request.</param>
|
||||
/// <returns>
|
||||
/// A <see cref="System.Threading.Tasks"/> containing a <see cref="Microsoft.Azure.Cosmos.ResourceResponse{T}"/> which wraps a <see cref="CosmosStoredProcedureSettings"/> containing the read resource record.
|
||||
/// A <see cref="System.Threading.Tasks"/> containing a <see cref="Microsoft.Azure.Cosmos.ResourceResponse{T}"/> which wraps a <see cref="StoredProcedure"/> containing the read resource record.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">If <paramref name="storedProcedureUri"/> is not set.</exception>
|
||||
/// <exception cref="DocumentClientException">This exception can encapsulate many different types of errors. To determine the specific error always look at the StatusCode property. Some common codes you may get when creating a Document are:
|
||||
|
@ -733,11 +734,11 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// Doing a read of a resource is the most efficient way to get a resource from the service. If you know the resource's ID, do a read instead of a query by ID.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <seealso cref="CosmosStoredProcedureSettings"/>
|
||||
/// <seealso cref="StoredProcedure"/>
|
||||
/// <seealso cref="Microsoft.Azure.Cosmos.RequestOptions"/>
|
||||
/// <seealso cref="Microsoft.Azure.Cosmos.ResourceResponse{T}"/>
|
||||
/// <seealso cref="System.Threading.Tasks.Task"/>
|
||||
public Task<ResourceResponse<CosmosStoredProcedureSettings>> ReadStoredProcedureAsync(Uri storedProcedureUri, RequestOptions options = null)
|
||||
public Task<ResourceResponse<StoredProcedure>> ReadStoredProcedureAsync(Uri storedProcedureUri, RequestOptions options = null)
|
||||
{
|
||||
if (storedProcedureUri == null)
|
||||
{
|
||||
|
@ -747,12 +748,12 @@ namespace Microsoft.Azure.Cosmos
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a <see cref="CosmosTriggerSettings"/> as an asynchronous operation from the Azure Cosmos DB service.
|
||||
/// Reads a <see cref="Trigger"/> as an asynchronous operation from the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <param name="triggerUri">A URI to the Trigger resource to be read.</param>
|
||||
/// <param name="options">The request options for the request.</param>
|
||||
/// <returns>
|
||||
/// A <see cref="System.Threading.Tasks"/> containing a <see cref="Microsoft.Azure.Cosmos.ResourceResponse{T}"/> which wraps a <see cref="CosmosTriggerSettings"/> containing the read resource record.
|
||||
/// A <see cref="System.Threading.Tasks"/> containing a <see cref="Microsoft.Azure.Cosmos.ResourceResponse{T}"/> which wraps a <see cref="Trigger"/> containing the read resource record.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">If <paramref name="triggerUri"/> is not set.</exception>
|
||||
/// <exception cref="DocumentClientException">This exception can encapsulate many different types of errors. To determine the specific error always look at the StatusCode property. Some common codes you may get when creating a Document are:
|
||||
|
@ -785,11 +786,11 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// Doing a read of a resource is the most efficient way to get a resource from the service. If you know the resource's ID, do a read instead of a query by ID.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <seealso cref="CosmosTriggerSettings"/>
|
||||
/// <seealso cref="Trigger"/>
|
||||
/// <seealso cref="Microsoft.Azure.Cosmos.RequestOptions"/>
|
||||
/// <seealso cref="Microsoft.Azure.Cosmos.ResourceResponse{T}"/>
|
||||
/// <seealso cref="System.Threading.Tasks.Task"/>
|
||||
public Task<ResourceResponse<CosmosTriggerSettings>> ReadTriggerAsync(Uri triggerUri, RequestOptions options = null)
|
||||
public Task<ResourceResponse<Trigger>> ReadTriggerAsync(Uri triggerUri, RequestOptions options = null)
|
||||
{
|
||||
if (triggerUri == null)
|
||||
{
|
||||
|
@ -799,7 +800,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a <see cref="CosmosUserDefinedFunctionSettings"/> as an asynchronous operation from the Azure Cosmos DB service.
|
||||
/// Reads a <see cref="UserDefinedFunction"/> as an asynchronous operation from the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <param name="functionUri">A URI to the User Defined Function resource to be read.</param>
|
||||
/// <param name="options">The request options for the request.</param>
|
||||
|
@ -837,11 +838,11 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// Doing a read of a resource is the most efficient way to get a resource from the service. If you know the resource's ID, do a read instead of a query by ID.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <seealso cref="CosmosUserDefinedFunctionSettings"/>
|
||||
/// <seealso cref="UserDefinedFunction"/>
|
||||
/// <seealso cref="Microsoft.Azure.Cosmos.RequestOptions"/>
|
||||
/// <seealso cref="Microsoft.Azure.Cosmos.ResourceResponse{T}"/>
|
||||
/// <seealso cref="System.Threading.Tasks.Task"/>
|
||||
public Task<ResourceResponse<CosmosUserDefinedFunctionSettings>> ReadUserDefinedFunctionAsync(Uri functionUri, RequestOptions options = null)
|
||||
public Task<ResourceResponse<UserDefinedFunction>> ReadUserDefinedFunctionAsync(Uri functionUri, RequestOptions options = null)
|
||||
{
|
||||
if (functionUri == null)
|
||||
{
|
||||
|
@ -1014,7 +1015,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// <param name="documentCollectionsUri">the URI for the document collections.</param>
|
||||
/// <param name="options">The request options for the request.</param>
|
||||
/// <returns>The task object representing the service response for the asynchronous operation.</returns>
|
||||
public Task<FeedResponse<CosmosContainerSettings>> ReadDocumentCollectionFeedAsync(Uri documentCollectionsUri, FeedOptions options = null)
|
||||
public Task<FeedResponse<DocumentCollection>> ReadDocumentCollectionFeedAsync(Uri documentCollectionsUri, FeedOptions options = null)
|
||||
{
|
||||
if (documentCollectionsUri == null)
|
||||
{
|
||||
|
@ -1029,7 +1030,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// <param name="storedProceduresUri">the URI for the stored procedures.</param>
|
||||
/// <param name="options">The request options for the request.</param>
|
||||
/// <returns>The task object representing the service response for the asynchronous operation.</returns>
|
||||
public Task<FeedResponse<CosmosStoredProcedureSettings>> ReadStoredProcedureFeedAsync(Uri storedProceduresUri, FeedOptions options = null)
|
||||
public Task<FeedResponse<StoredProcedure>> ReadStoredProcedureFeedAsync(Uri storedProceduresUri, FeedOptions options = null)
|
||||
{
|
||||
if (storedProceduresUri == null)
|
||||
{
|
||||
|
@ -1044,7 +1045,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// <param name="triggersUri">the URI for the triggers.</param>
|
||||
/// <param name="options">The request options for the request.</param>
|
||||
/// <returns>The task object representing the service response for the asynchronous operation.</returns>
|
||||
public Task<FeedResponse<CosmosTriggerSettings>> ReadTriggerFeedAsync(Uri triggersUri, FeedOptions options = null)
|
||||
public Task<FeedResponse<Trigger>> ReadTriggerFeedAsync(Uri triggersUri, FeedOptions options = null)
|
||||
{
|
||||
if (triggersUri == null)
|
||||
{
|
||||
|
@ -1059,7 +1060,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// <param name="userDefinedFunctionsUri">the URI for the user defined functions.</param>
|
||||
/// <param name="options">The request options for the request.</param>
|
||||
/// <returns>The task object representing the service response for the asynchronous operation.</returns>
|
||||
public Task<FeedResponse<CosmosUserDefinedFunctionSettings>> ReadUserDefinedFunctionFeedAsync(Uri userDefinedFunctionsUri, FeedOptions options = null)
|
||||
public Task<FeedResponse<UserDefinedFunction>> ReadUserDefinedFunctionFeedAsync(Uri userDefinedFunctionsUri, FeedOptions options = null)
|
||||
{
|
||||
if (userDefinedFunctionsUri == null)
|
||||
{
|
||||
|
@ -1234,7 +1235,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// <param name="databaseUri">the URI to the database.</param>
|
||||
/// <param name="feedOptions">The options for processing the query results feed.</param>
|
||||
/// <returns>The query result set.</returns>
|
||||
public IOrderedQueryable<CosmosContainerSettings> CreateDocumentCollectionQuery(Uri databaseUri, FeedOptions feedOptions = null)
|
||||
public IOrderedQueryable<DocumentCollection> CreateDocumentCollectionQuery(Uri databaseUri, FeedOptions feedOptions = null)
|
||||
{
|
||||
if (databaseUri == null)
|
||||
{
|
||||
|
@ -1282,7 +1283,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// <param name="databaseUri">Specifies the database to read collections from.</param>
|
||||
/// <param name="feedOptions">Specifies the options for processing the query results feed.</param>
|
||||
/// <returns>the query result set.</returns>
|
||||
internal IDocumentQuery<CosmosContainerSettings> CreateDocumentCollectionChangeFeedQuery(Uri databaseUri, ChangeFeedOptions feedOptions)
|
||||
internal IDocumentQuery<DocumentCollection> CreateDocumentCollectionChangeFeedQuery(Uri databaseUri, ChangeFeedOptions feedOptions)
|
||||
{
|
||||
if(databaseUri == null)
|
||||
{
|
||||
|
@ -1298,7 +1299,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// <param name="storedProceduresUri">the URI to the stored procedures.</param>
|
||||
/// <param name="feedOptions">The options for processing the query results feed.</param>
|
||||
/// <returns>The query result set.</returns>
|
||||
public IOrderedQueryable<CosmosStoredProcedureSettings> CreateStoredProcedureQuery(Uri storedProceduresUri, FeedOptions feedOptions = null)
|
||||
public IOrderedQueryable<StoredProcedure> CreateStoredProcedureQuery(Uri storedProceduresUri, FeedOptions feedOptions = null)
|
||||
{
|
||||
if (storedProceduresUri == null)
|
||||
{
|
||||
|
@ -1345,7 +1346,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// <param name="triggersUri">the URI to the triggers.</param>
|
||||
/// <param name="feedOptions">The options for processing the query results feed.</param>
|
||||
/// <returns>The query result set.</returns>
|
||||
public IOrderedQueryable<CosmosTriggerSettings> CreateTriggerQuery(Uri triggersUri, FeedOptions feedOptions = null)
|
||||
public IOrderedQueryable<Trigger> CreateTriggerQuery(Uri triggersUri, FeedOptions feedOptions = null)
|
||||
{
|
||||
if (triggersUri == null)
|
||||
{
|
||||
|
@ -1392,7 +1393,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// <param name="userDefinedFunctionsUri">the URI to the user-defined functions.</param>
|
||||
/// <param name="feedOptions">The options for processing the query results feed.</param>
|
||||
/// <returns>The query result set.</returns>
|
||||
public IOrderedQueryable<CosmosUserDefinedFunctionSettings> CreateUserDefinedFunctionQuery(Uri userDefinedFunctionsUri, FeedOptions feedOptions = null)
|
||||
public IOrderedQueryable<UserDefinedFunction> CreateUserDefinedFunctionQuery(Uri userDefinedFunctionsUri, FeedOptions feedOptions = null)
|
||||
{
|
||||
if (userDefinedFunctionsUri == null)
|
||||
{
|
||||
|
|
|
@ -1,89 +0,0 @@
|
|||
//------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------
|
||||
namespace Microsoft.Azure.Cosmos
|
||||
{
|
||||
using Newtonsoft.Json;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the template class used by methods returning single objects in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <typeparam name="TDocument">the document type.</typeparam>
|
||||
/// <remarks>
|
||||
/// Response from type-specific read of Document resource(ReadDocumentAsync{TDocument}) returns the response wrapped in a
|
||||
/// DocumentResponse object. This contains the metadata from the response headers from the Azure Cosmos DB call including
|
||||
/// the request units (RequestCharge), activity ID, quotas/usage of resources and the typed document object(TDocument).
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// The following example extracts the CustomerName property, request units consumed, activity ID and StatusCode from a ReadDocumentAsync{Customer} call.
|
||||
/// <code language="c#">
|
||||
/// <![CDATA[
|
||||
/// DocumentResponse<Customer> response = await client.ReadDocumentAsync<Customer>(documentLink);
|
||||
/// Console.WriteLine(response.Document.CustomerName);
|
||||
/// Console.WriteLine(response.RequestCharge);
|
||||
/// Console.WriteLine(response.ActivityId);
|
||||
/// Console.WriteLine(response.StatusCode); // HttpStatusCode.Created or 201
|
||||
/// ]]>
|
||||
/// </code>
|
||||
/// </example>
|
||||
internal sealed class DocumentResponse<TDocument> : ResourceResponseBase, IDocumentResponse<TDocument>
|
||||
{
|
||||
private TDocument document;
|
||||
private JsonSerializerSettings settings;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor exposed for mocking purposes for the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public DocumentResponse()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor exposed for mocking purposes for the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <param name="document"></param>
|
||||
public DocumentResponse(TDocument document)
|
||||
:this()
|
||||
{
|
||||
this.document = document;
|
||||
}
|
||||
|
||||
internal DocumentResponse(DocumentServiceResponse response, JsonSerializerSettings settings = null)
|
||||
:base(response)
|
||||
{
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the document returned in the response from the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The document returned in the response.
|
||||
/// </value>
|
||||
public TDocument Document
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.document == null)
|
||||
{
|
||||
Document doc = this.response.GetResource<Document>();
|
||||
doc.SerializerSettings = this.settings;
|
||||
this.document = (TDocument)(dynamic)doc;
|
||||
}
|
||||
return this.document;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the document in the response implicitly from the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <param name="source">The DocumentResponse source.</param>
|
||||
/// <returns>The document object.</returns>
|
||||
public static implicit operator TDocument(DocumentResponse<TDocument> source)
|
||||
{
|
||||
return source.Document;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,405 +1,406 @@
|
|||
//------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------
|
||||
namespace Microsoft.Azure.Cosmos
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the options associated with feed methods (enumeration operations) in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Used to manage query and ReadFeed execution. Can use FeedOptions to set page size (MaxItemCount)
|
||||
/// </remarks>
|
||||
internal sealed class FeedOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FeedOptions"/> class for the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public FeedOptions()
|
||||
{
|
||||
}
|
||||
|
||||
internal FeedOptions(FeedOptions options)
|
||||
{
|
||||
if (options == null)
|
||||
{
|
||||
throw new ArgumentNullException("options");
|
||||
}
|
||||
|
||||
this.MaxItemCount = options.MaxItemCount;
|
||||
this.RequestContinuation = options.RequestContinuation;
|
||||
this.SessionToken = options.SessionToken;
|
||||
this.EnableScanInQuery = options.EnableScanInQuery;
|
||||
this.EnableCrossPartitionQuery = options.EnableCrossPartitionQuery;
|
||||
this.EnableLowPrecisionOrderBy = options.EnableLowPrecisionOrderBy;
|
||||
this.MaxBufferedItemCount = options.MaxBufferedItemCount;
|
||||
this.MaxDegreeOfParallelism = options.MaxDegreeOfParallelism;
|
||||
this.PartitionKeyRangeId = options.PartitionKeyRangeId;
|
||||
this.PopulateQueryMetrics = options.PopulateQueryMetrics;
|
||||
this.ResponseContinuationTokenLimitInKb = options.ResponseContinuationTokenLimitInKb;
|
||||
|
||||
if (options.PartitionKey == null)
|
||||
{
|
||||
this.PartitionKey = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.PartitionKey = PartitionKey.FromInternalKey(options.PartitionKey.InternalKey);
|
||||
}
|
||||
|
||||
this.EmitVerboseTracesInQuery = options.EmitVerboseTracesInQuery;
|
||||
this.FilterBySchemaResourceId = options.FilterBySchemaResourceId;
|
||||
this.RequestContinuation = options.RequestContinuation;
|
||||
this.ConsistencyLevel = options.ConsistencyLevel;
|
||||
this.JsonSerializerSettings = options.JsonSerializerSettings;
|
||||
this.ForceQueryScan = options.ForceQueryScan;
|
||||
this.EnumerationDirection = options.EnumerationDirection;
|
||||
this.ReadFeedKeyType = options.ReadFeedKeyType;
|
||||
this.StartId = options.StartId;
|
||||
this.EndId = options.EndId;
|
||||
this.StartEpk = options.StartEpk;
|
||||
this.EndEpk = options.EndEpk;
|
||||
this.ContentSerializationFormat = options.ContentSerializationFormat;
|
||||
this.CosmosSerializationOptions = options.CosmosSerializationOptions;
|
||||
this.Properties = options.Properties;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the maximum number of items to be returned in the enumeration operation in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The maximum number of items to be returned in the enumeration operation.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// Used for query pagination.
|
||||
/// '-1' Used for dynamic page size.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code language="c#">
|
||||
/// <![CDATA[
|
||||
/// // Fetch query results 10 at a time.
|
||||
/// using (var queryable = client.CreateDocumentQuery<Book>(collectionLink, new FeedOptions { MaxItemCount = 10 }))
|
||||
/// {
|
||||
/// while (queryable.HasResults)
|
||||
/// {
|
||||
/// FeedResponse<Book> response = await queryable.ExecuteNext<Book>();
|
||||
/// }
|
||||
/// }
|
||||
/// ]]>
|
||||
/// </code>
|
||||
/// </example>
|
||||
public int? MaxItemCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the request continuation token in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The request continuation token.
|
||||
/// </value>
|
||||
/// <example>
|
||||
/// <code language="c#">
|
||||
/// <![CDATA[
|
||||
/// // Resume query execution using the continuation from the previous query
|
||||
/// var queryable = client.CreateDocumentQuery<Book>(collectionLink, new FeedOptions { RequestContinuation = prevQuery.ResponseContinuation });
|
||||
/// ]]>
|
||||
/// </code>
|
||||
/// </example>
|
||||
public string RequestContinuation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the session token for use with session consistency in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The session token for use with session consistency.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// Useful for applications that are load balanced across multiple Microsoft.Azure.Documents.Client.DocumentClient instances.
|
||||
/// In this case, round-trip the token from end user to the application and then back to Azure Cosmos DB so that a session
|
||||
/// can be preserved across servers.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code language="c#">
|
||||
/// <![CDATA[
|
||||
/// var queryable = client.CreateDocumentQuery<Book>(
|
||||
/// collectionLink, new FeedOptions { SessionToken = lastSessionToken });
|
||||
/// ]]>
|
||||
/// </code>
|
||||
/// </example>
|
||||
public string SessionToken { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the option to enable scans on the queries which couldn't be served
|
||||
/// as indexing was opted out on the requested paths in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Option is true if scan on queries is enabled; otherwise, false.
|
||||
/// </value>
|
||||
/// <example>
|
||||
/// <code language="c#">
|
||||
/// <![CDATA[
|
||||
/// // Enable scan when Range index is not specified.
|
||||
/// var queryable = client.CreateDocumentQuery<Book>(
|
||||
/// collectionLink, new FeedOptions { EnableScanInQuery = true }).Where(b => b.Price > 1000);
|
||||
/// ]]>
|
||||
/// </code>
|
||||
/// </example>
|
||||
public bool? EnableScanInQuery { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether users are enabled to send more than one request to execute
|
||||
/// the query in the Azure Cosmos DB service. More than one request is necessary if the query
|
||||
/// is not scoped to single partition key value.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Option is true if cross-partition query execution is enabled; otherwise, false.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This option only applies to queries on documents and document attachments.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code language="c#">
|
||||
/// <![CDATA[
|
||||
/// // Enable cross partition query.
|
||||
/// var queryable = client.CreateDocumentQuery<Book>(
|
||||
/// collectionLink, new FeedOptions { EnableCrossPartitionQuery = true }).Where(b => b.Price > 1000);
|
||||
/// ]]>
|
||||
/// </code>
|
||||
/// </example>
|
||||
public bool EnableCrossPartitionQuery { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the option to enable low precision order by in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The option to enable low-precision order by.
|
||||
/// </value>
|
||||
public bool? EnableLowPrecisionOrderBy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="PartitionKey"/> for the current request in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Partition key is required when read documents or attachments feed in a partitioned collection.
|
||||
/// Specifically Partition key is required for :
|
||||
/// <see cref="DocumentClient.ReadDocumentFeedAsync(string, FeedOptions, CancellationToken)"/> and
|
||||
/// <see cref="DocumentClient.ReadConflictFeedAsync(string, FeedOptions)"/>.
|
||||
/// Only documents in partitions containing the <see cref="PartitionKey"/> is returned in the result.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// The following example shows how to read a document feed in a partitioned collection using <see cref="PartitionKey"/>.
|
||||
/// The example assumes the collection is created with a <see cref="PartitionKeyDefinition"/> on the 'country' property in all the documents.
|
||||
/// <code language="c#">
|
||||
/// <![CDATA[
|
||||
/// await client.ReadDocumentFeedAsync(
|
||||
/// collection.SelfLink,
|
||||
/// new RequestOptions { PartitionKey = new PartitionKey("USA") } );
|
||||
/// ]]>
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// <seealso cref="CosmosContainerSettings"/>
|
||||
/// <seealso cref="Microsoft.Azure.Cosmos.PartitionKeyDefinition"/>
|
||||
public PartitionKey PartitionKey { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the partition key range id for the current request.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// ReadFeed requests can use this to forward request to specific range.
|
||||
/// This is usefull in case of bulk export scenarios.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// The following example shows how to read a document feed in a partitioned collection from partition key range "20".
|
||||
/// <code language="c#">
|
||||
/// <![CDATA[
|
||||
/// await client.ReadDocumentFeedAsync(
|
||||
/// collection.SelfLink,
|
||||
/// new RequestOptions { PartitionKeyRangeId = "20" } );
|
||||
/// ]]>
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// <seealso cref="CosmosContainerSettings"/>
|
||||
public string PartitionKeyRangeId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the number of concurrent operations run client side during
|
||||
/// parallel query execution in the Azure Cosmos DB service.
|
||||
/// A positive property value limits the number of
|
||||
/// concurrent operations to the set value. If it is set to less than 0, the
|
||||
/// system automatically decides the number of concurrent operations to run.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The maximum number of concurrent operations during parallel execution. Defaults to 0.
|
||||
/// </value>
|
||||
/// <example>
|
||||
/// <code language="c#">
|
||||
/// <![CDATA[
|
||||
/// var queryable = client.CreateDocumentQuery<Book>(collectionLink, new FeedOptions {
|
||||
/// MaxDegreeOfParallelism = 5});
|
||||
/// ]]>
|
||||
/// </code>
|
||||
/// </example>
|
||||
public int MaxDegreeOfParallelism { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the maximum number of items that can be buffered client side during
|
||||
/// parallel query execution in the Azure Cosmos DB service.
|
||||
/// A positive property value limits the number of buffered
|
||||
/// items to the set value. If it is set to less than 0, the system automatically
|
||||
/// decides the number of items to buffer.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The maximum count of items that can be buffered during parallel query execution.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// This is only suggestive and cannot be abided by in certain cases.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code language="c#">
|
||||
/// <![CDATA[
|
||||
/// var queryable = client.CreateDocumentQuery<Book>(collectionLink, new FeedOptions {
|
||||
/// MaximumBufferSize = 10, MaxDegreeOfParallelism = 2 });
|
||||
/// ]]>
|
||||
/// </code>
|
||||
/// </example>
|
||||
public int MaxBufferedItemCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the option to allow queries to emit out verbose traces
|
||||
/// for investigation in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Option is true if query tracing is enabled; otherwise, false.
|
||||
/// </value>
|
||||
internal bool? EmitVerboseTracesInQuery { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the schema rid which could be used to filter the document feed response
|
||||
/// in order to focus on the documents for a particular schema.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// By default, it is <c>null</c> which means no filtering will be applied.
|
||||
/// Otherwise, it must be a valid resource id of Schema resource.
|
||||
/// </value>
|
||||
internal string FilterBySchemaResourceId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="PopulateQueryMetrics"/> request option for document query requests in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// PopulateQueryMetrics is used to enable/disable getting metrics relating to query execution on document query requests.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public bool PopulateQueryMetrics { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="ResponseContinuationTokenLimitInKb"/> request option for document query requests in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// ResponseContinuationTokenLimitInKb is used to limit the length of continuation token in the query response. Valid values are >= 0.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public int? ResponseContinuationTokenLimitInKb { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="JsonSerializerSettings"/> for the current request used to deserialize the document.
|
||||
/// If null, uses the default serializer settings set up in the DocumentClient.
|
||||
/// </summary>
|
||||
public JsonSerializerSettings JsonSerializerSettings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the consistency level required for the feed (query/read feed) operation in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The consistency level required for the request.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// Azure Cosmos DB offers 5 different consistency levels. Strong, Bounded Staleness, Session, Consistent Prefix and Eventual - in order of strongest to weakest consistency. <see cref="ConnectionPolicy"/>
|
||||
///
|
||||
/// Azure Cosmos query/DB feed operations may be retrieved from many partitions, each accessed across many round trips. The consistency level is honored only within a partition and round trip.
|
||||
/// <para>
|
||||
/// While this is set at a database account level, Azure Cosmos DB allows a developer to override the default consistency level
|
||||
/// for each individual request.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// This example uses FeedOptions to override the consistency level to Eventual.
|
||||
/// <code language="c#">
|
||||
/// <![CDATA[
|
||||
/// Document doc = client.ReadDocumentFeedAsync(documentLink, new FeedOptions { ConsistencyLevel = ConsistencyLevel.Eventual });
|
||||
/// ]]>
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// <seealso cref="ConsistencyLevel"/>
|
||||
public ConsistencyLevel? ConsistencyLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the flag that tells the backend to forces the query to perform a scan (at a request level).
|
||||
/// </summary>
|
||||
internal bool ForceQueryScan { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the EnumerationDirection
|
||||
/// To be used along with Read feed operation
|
||||
/// </summary>
|
||||
internal EnumerationDirection? EnumerationDirection { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the ReadFeedKeyType
|
||||
/// To be used along with Read feed operation
|
||||
/// </summary>
|
||||
internal ReadFeedKeyType? ReadFeedKeyType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the StartId
|
||||
/// To be used along with Read feed operation
|
||||
/// </summary>
|
||||
internal string StartId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the EndId
|
||||
/// To be used along with Read feed operation
|
||||
/// </summary>
|
||||
internal string EndId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the StartEpk
|
||||
/// To be used along with Read feed operation
|
||||
/// </summary>
|
||||
internal string StartEpk { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the EndEpk
|
||||
/// To be used along with Read feed operation
|
||||
/// </summary>
|
||||
internal string EndEpk { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the ContentSerializationFormat for the feed (query/read feed) operation in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If the document is stored in a different serialization format then the one requested, then there will be a rewrite over the wire, but the source document will be untouched.
|
||||
/// </remarks>
|
||||
internal ContentSerializationFormat? ContentSerializationFormat { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the custom serialization options for query
|
||||
/// </summary>
|
||||
internal CosmosSerializationOptions CosmosSerializationOptions { get; set; }
|
||||
|
||||
internal IDictionary<string, object> Properties { get; set; }
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------
|
||||
namespace Microsoft.Azure.Cosmos
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Documents;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the options associated with feed methods (enumeration operations) in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Used to manage query and ReadFeed execution. Can use FeedOptions to set page size (MaxItemCount)
|
||||
/// </remarks>
|
||||
internal sealed class FeedOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FeedOptions"/> class for the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
public FeedOptions()
|
||||
{
|
||||
}
|
||||
|
||||
internal FeedOptions(FeedOptions options)
|
||||
{
|
||||
if (options == null)
|
||||
{
|
||||
throw new ArgumentNullException("options");
|
||||
}
|
||||
|
||||
this.MaxItemCount = options.MaxItemCount;
|
||||
this.RequestContinuation = options.RequestContinuation;
|
||||
this.SessionToken = options.SessionToken;
|
||||
this.EnableScanInQuery = options.EnableScanInQuery;
|
||||
this.EnableCrossPartitionQuery = options.EnableCrossPartitionQuery;
|
||||
this.EnableLowPrecisionOrderBy = options.EnableLowPrecisionOrderBy;
|
||||
this.MaxBufferedItemCount = options.MaxBufferedItemCount;
|
||||
this.MaxDegreeOfParallelism = options.MaxDegreeOfParallelism;
|
||||
this.PartitionKeyRangeId = options.PartitionKeyRangeId;
|
||||
this.PopulateQueryMetrics = options.PopulateQueryMetrics;
|
||||
this.ResponseContinuationTokenLimitInKb = options.ResponseContinuationTokenLimitInKb;
|
||||
|
||||
if (options.PartitionKey == null)
|
||||
{
|
||||
this.PartitionKey = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.PartitionKey = PartitionKey.FromInternalKey(options.PartitionKey.InternalKey);
|
||||
}
|
||||
|
||||
this.EmitVerboseTracesInQuery = options.EmitVerboseTracesInQuery;
|
||||
this.FilterBySchemaResourceId = options.FilterBySchemaResourceId;
|
||||
this.RequestContinuation = options.RequestContinuation;
|
||||
this.ConsistencyLevel = options.ConsistencyLevel;
|
||||
this.JsonSerializerSettings = options.JsonSerializerSettings;
|
||||
this.ForceQueryScan = options.ForceQueryScan;
|
||||
this.EnumerationDirection = options.EnumerationDirection;
|
||||
this.ReadFeedKeyType = options.ReadFeedKeyType;
|
||||
this.StartId = options.StartId;
|
||||
this.EndId = options.EndId;
|
||||
this.StartEpk = options.StartEpk;
|
||||
this.EndEpk = options.EndEpk;
|
||||
this.ContentSerializationFormat = options.ContentSerializationFormat;
|
||||
this.CosmosSerializationOptions = options.CosmosSerializationOptions;
|
||||
this.Properties = options.Properties;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the maximum number of items to be returned in the enumeration operation in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The maximum number of items to be returned in the enumeration operation.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// Used for query pagination.
|
||||
/// '-1' Used for dynamic page size.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code language="c#">
|
||||
/// <![CDATA[
|
||||
/// // Fetch query results 10 at a time.
|
||||
/// using (var queryable = client.CreateDocumentQuery<Book>(collectionLink, new FeedOptions { MaxItemCount = 10 }))
|
||||
/// {
|
||||
/// while (queryable.HasResults)
|
||||
/// {
|
||||
/// FeedResponse<Book> response = await queryable.ExecuteNext<Book>();
|
||||
/// }
|
||||
/// }
|
||||
/// ]]>
|
||||
/// </code>
|
||||
/// </example>
|
||||
public int? MaxItemCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the request continuation token in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The request continuation token.
|
||||
/// </value>
|
||||
/// <example>
|
||||
/// <code language="c#">
|
||||
/// <![CDATA[
|
||||
/// // Resume query execution using the continuation from the previous query
|
||||
/// var queryable = client.CreateDocumentQuery<Book>(collectionLink, new FeedOptions { RequestContinuation = prevQuery.ResponseContinuation });
|
||||
/// ]]>
|
||||
/// </code>
|
||||
/// </example>
|
||||
public string RequestContinuation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the session token for use with session consistency in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The session token for use with session consistency.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// Useful for applications that are load balanced across multiple Microsoft.Azure.Documents.Client.DocumentClient instances.
|
||||
/// In this case, round-trip the token from end user to the application and then back to Azure Cosmos DB so that a session
|
||||
/// can be preserved across servers.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code language="c#">
|
||||
/// <![CDATA[
|
||||
/// var queryable = client.CreateDocumentQuery<Book>(
|
||||
/// collectionLink, new FeedOptions { SessionToken = lastSessionToken });
|
||||
/// ]]>
|
||||
/// </code>
|
||||
/// </example>
|
||||
public string SessionToken { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the option to enable scans on the queries which couldn't be served
|
||||
/// as indexing was opted out on the requested paths in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Option is true if scan on queries is enabled; otherwise, false.
|
||||
/// </value>
|
||||
/// <example>
|
||||
/// <code language="c#">
|
||||
/// <![CDATA[
|
||||
/// // Enable scan when Range index is not specified.
|
||||
/// var queryable = client.CreateDocumentQuery<Book>(
|
||||
/// collectionLink, new FeedOptions { EnableScanInQuery = true }).Where(b => b.Price > 1000);
|
||||
/// ]]>
|
||||
/// </code>
|
||||
/// </example>
|
||||
public bool? EnableScanInQuery { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether users are enabled to send more than one request to execute
|
||||
/// the query in the Azure Cosmos DB service. More than one request is necessary if the query
|
||||
/// is not scoped to single partition key value.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Option is true if cross-partition query execution is enabled; otherwise, false.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This option only applies to queries on documents and document attachments.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code language="c#">
|
||||
/// <![CDATA[
|
||||
/// // Enable cross partition query.
|
||||
/// var queryable = client.CreateDocumentQuery<Book>(
|
||||
/// collectionLink, new FeedOptions { EnableCrossPartitionQuery = true }).Where(b => b.Price > 1000);
|
||||
/// ]]>
|
||||
/// </code>
|
||||
/// </example>
|
||||
public bool EnableCrossPartitionQuery { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the option to enable low precision order by in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The option to enable low-precision order by.
|
||||
/// </value>
|
||||
public bool? EnableLowPrecisionOrderBy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="PartitionKey"/> for the current request in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Partition key is required when read documents or attachments feed in a partitioned collection.
|
||||
/// Specifically Partition key is required for :
|
||||
/// <see cref="DocumentClient.ReadDocumentFeedAsync(string, FeedOptions, CancellationToken)"/> and
|
||||
/// <see cref="DocumentClient.ReadConflictFeedAsync(string, FeedOptions)"/>.
|
||||
/// Only documents in partitions containing the <see cref="PartitionKey"/> is returned in the result.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// The following example shows how to read a document feed in a partitioned collection using <see cref="PartitionKey"/>.
|
||||
/// The example assumes the collection is created with a <see cref="PartitionKeyDefinition"/> on the 'country' property in all the documents.
|
||||
/// <code language="c#">
|
||||
/// <![CDATA[
|
||||
/// await client.ReadDocumentFeedAsync(
|
||||
/// collection.SelfLink,
|
||||
/// new RequestOptions { PartitionKey = new PartitionKey("USA") } );
|
||||
/// ]]>
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// <seealso cref="CosmosContainerSettings"/>
|
||||
/// <seealso cref="Microsoft.Azure.Cosmos.PartitionKeyDefinition"/>
|
||||
public PartitionKey PartitionKey { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the partition key range id for the current request.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// ReadFeed requests can use this to forward request to specific range.
|
||||
/// This is usefull in case of bulk export scenarios.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// The following example shows how to read a document feed in a partitioned collection from partition key range "20".
|
||||
/// <code language="c#">
|
||||
/// <![CDATA[
|
||||
/// await client.ReadDocumentFeedAsync(
|
||||
/// collection.SelfLink,
|
||||
/// new RequestOptions { PartitionKeyRangeId = "20" } );
|
||||
/// ]]>
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// <seealso cref="CosmosContainerSettings"/>
|
||||
public string PartitionKeyRangeId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the number of concurrent operations run client side during
|
||||
/// parallel query execution in the Azure Cosmos DB service.
|
||||
/// A positive property value limits the number of
|
||||
/// concurrent operations to the set value. If it is set to less than 0, the
|
||||
/// system automatically decides the number of concurrent operations to run.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The maximum number of concurrent operations during parallel execution. Defaults to 0.
|
||||
/// </value>
|
||||
/// <example>
|
||||
/// <code language="c#">
|
||||
/// <![CDATA[
|
||||
/// var queryable = client.CreateDocumentQuery<Book>(collectionLink, new FeedOptions {
|
||||
/// MaxDegreeOfParallelism = 5});
|
||||
/// ]]>
|
||||
/// </code>
|
||||
/// </example>
|
||||
public int MaxDegreeOfParallelism { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the maximum number of items that can be buffered client side during
|
||||
/// parallel query execution in the Azure Cosmos DB service.
|
||||
/// A positive property value limits the number of buffered
|
||||
/// items to the set value. If it is set to less than 0, the system automatically
|
||||
/// decides the number of items to buffer.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The maximum count of items that can be buffered during parallel query execution.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// This is only suggestive and cannot be abided by in certain cases.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code language="c#">
|
||||
/// <![CDATA[
|
||||
/// var queryable = client.CreateDocumentQuery<Book>(collectionLink, new FeedOptions {
|
||||
/// MaximumBufferSize = 10, MaxDegreeOfParallelism = 2 });
|
||||
/// ]]>
|
||||
/// </code>
|
||||
/// </example>
|
||||
public int MaxBufferedItemCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the option to allow queries to emit out verbose traces
|
||||
/// for investigation in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Option is true if query tracing is enabled; otherwise, false.
|
||||
/// </value>
|
||||
internal bool? EmitVerboseTracesInQuery { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the schema rid which could be used to filter the document feed response
|
||||
/// in order to focus on the documents for a particular schema.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// By default, it is <c>null</c> which means no filtering will be applied.
|
||||
/// Otherwise, it must be a valid resource id of Schema resource.
|
||||
/// </value>
|
||||
internal string FilterBySchemaResourceId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="PopulateQueryMetrics"/> request option for document query requests in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// PopulateQueryMetrics is used to enable/disable getting metrics relating to query execution on document query requests.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public bool PopulateQueryMetrics { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="ResponseContinuationTokenLimitInKb"/> request option for document query requests in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// ResponseContinuationTokenLimitInKb is used to limit the length of continuation token in the query response. Valid values are >= 0.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public int? ResponseContinuationTokenLimitInKb { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="JsonSerializerSettings"/> for the current request used to deserialize the document.
|
||||
/// If null, uses the default serializer settings set up in the DocumentClient.
|
||||
/// </summary>
|
||||
public JsonSerializerSettings JsonSerializerSettings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the consistency level required for the feed (query/read feed) operation in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The consistency level required for the request.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// Azure Cosmos DB offers 5 different consistency levels. Strong, Bounded Staleness, Session, Consistent Prefix and Eventual - in order of strongest to weakest consistency. <see cref="ConnectionPolicy"/>
|
||||
///
|
||||
/// Azure Cosmos query/DB feed operations may be retrieved from many partitions, each accessed across many round trips. The consistency level is honored only within a partition and round trip.
|
||||
/// <para>
|
||||
/// While this is set at a database account level, Azure Cosmos DB allows a developer to override the default consistency level
|
||||
/// for each individual request.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// This example uses FeedOptions to override the consistency level to Eventual.
|
||||
/// <code language="c#">
|
||||
/// <![CDATA[
|
||||
/// Document doc = client.ReadDocumentFeedAsync(documentLink, new FeedOptions { ConsistencyLevel = ConsistencyLevel.Eventual });
|
||||
/// ]]>
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// <seealso cref="ConsistencyLevel"/>
|
||||
public ConsistencyLevel? ConsistencyLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the flag that tells the backend to forces the query to perform a scan (at a request level).
|
||||
/// </summary>
|
||||
internal bool ForceQueryScan { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the EnumerationDirection
|
||||
/// To be used along with Read feed operation
|
||||
/// </summary>
|
||||
internal EnumerationDirection? EnumerationDirection { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the ReadFeedKeyType
|
||||
/// To be used along with Read feed operation
|
||||
/// </summary>
|
||||
internal ReadFeedKeyType? ReadFeedKeyType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the StartId
|
||||
/// To be used along with Read feed operation
|
||||
/// </summary>
|
||||
internal string StartId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the EndId
|
||||
/// To be used along with Read feed operation
|
||||
/// </summary>
|
||||
internal string EndId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the StartEpk
|
||||
/// To be used along with Read feed operation
|
||||
/// </summary>
|
||||
internal string StartEpk { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the EndEpk
|
||||
/// To be used along with Read feed operation
|
||||
/// </summary>
|
||||
internal string EndEpk { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the ContentSerializationFormat for the feed (query/read feed) operation in the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If the document is stored in a different serialization format then the one requested, then there will be a rewrite over the wire, but the source document will be untouched.
|
||||
/// </remarks>
|
||||
internal ContentSerializationFormat? ContentSerializationFormat { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the custom serialization options for query
|
||||
/// </summary>
|
||||
internal CosmosSerializationOptions CosmosSerializationOptions { get; set; }
|
||||
|
||||
internal IDictionary<string, object> Properties { get; set; }
|
||||
}
|
||||
}
|
|
@ -15,6 +15,8 @@ namespace Microsoft.Azure.Cosmos
|
|||
using System.Reflection;
|
||||
using Microsoft.Azure.Cosmos.Collections;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Documents;
|
||||
using Microsoft.Azure.Documents.Collections;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the template class used by feed methods (enumeration operations) for the Azure Cosmos DB service.
|
||||
|
|
|
@ -9,10 +9,9 @@ namespace Microsoft.Azure.Cosmos
|
|||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.Azure.Cosmos.CosmosElements;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Cosmos.Json;
|
||||
using Microsoft.Azure.Documents;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using JsonWriter = Json.JsonWriter;
|
||||
|
||||
internal static class FeedResponseBinder
|
||||
|
@ -80,8 +79,8 @@ namespace Microsoft.Azure.Cosmos
|
|||
|
||||
// If the resource type is an offer and the requested type is either a Offer or OfferV2 or dynamic
|
||||
// create a OfferV2 object and cast it to T. This is a temporary fix until offers is moved to v3 API.
|
||||
if (resourceType == ResourceType.Offer &&
|
||||
(typeof(T).IsSubclassOf(typeof(CosmosResource)) || typeof(T) == typeof(object)))
|
||||
if (resourceType == ResourceType.Offer &&
|
||||
(typeof(T).IsSubclassOf(typeof(Resource)) || typeof(T) == typeof(object)))
|
||||
{
|
||||
typedResults = JsonConvert.DeserializeObject<List<OfferV2>>(jsonText, settings).Cast<T>();
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@ namespace Microsoft.Azure.Cosmos
|
|||
using Microsoft.Azure.Cosmos.Collections;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Cosmos.Routing;
|
||||
using Microsoft.Azure.Documents;
|
||||
using Microsoft.Azure.Documents.Collections;
|
||||
|
||||
internal sealed class GatewayAccountReader
|
||||
{
|
||||
|
@ -78,9 +80,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
{
|
||||
using (DocumentServiceResponse documentServiceResponse = await ClientExtensions.ParseResponseAsync(responseMessage))
|
||||
{
|
||||
CosmosAccountSettings databaseAccount = documentServiceResponse.GetInternalResource<CosmosAccountSettings>(CosmosAccountSettings.CreateNewInstance);
|
||||
|
||||
return databaseAccount;
|
||||
return CosmosResource.FromStream<CosmosAccountSettings>(documentServiceResponse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@ namespace Microsoft.Azure.Cosmos
|
|||
using Microsoft.Azure.Cosmos.Collections;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Cosmos.Routing;
|
||||
using Microsoft.Azure.Documents;
|
||||
using Microsoft.Azure.Documents.Collections;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
// Marking it as non-sealed in order to unit test it using Moq framework
|
||||
|
@ -105,7 +107,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
{
|
||||
using (DocumentServiceResponse documentServiceResponse = await ClientExtensions.ParseResponseAsync(responseMessage))
|
||||
{
|
||||
databaseAccount = documentServiceResponse.GetInternalResource<CosmosAccountSettings>(CosmosAccountSettings.CreateNewInstance);
|
||||
databaseAccount = CosmosResource.FromStream<CosmosAccountSettings>(documentServiceResponse);
|
||||
}
|
||||
|
||||
long longValue;
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace Microsoft.Azure.Cosmos.Handlers
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Documents;
|
||||
|
||||
internal abstract class AbstractRetryHandler : CosmosRequestHandler
|
||||
{
|
||||
|
|
|
@ -14,6 +14,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.Cosmos.Common;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Documents;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a request in the processing pipeline of the Azure Cosmos DB SDK.
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Documents;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a response from the Azure Cosmos DB service.
|
||||
|
|
|
@ -8,6 +8,7 @@ namespace Microsoft.Azure.Cosmos.Handlers
|
|||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Documents;
|
||||
|
||||
/// <summary>
|
||||
/// Handler to ensure that CollectionCache and PartitionRoutingMap for a given collection exists
|
||||
|
|
|
@ -14,9 +14,11 @@ namespace Microsoft.Azure.Cosmos.Handlers
|
|||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Cosmos.Query;
|
||||
using Microsoft.Azure.Cosmos.Routing;
|
||||
using Microsoft.Azure.Documents;
|
||||
using Microsoft.Azure.Documents.Routing;
|
||||
using Newtonsoft.Json;
|
||||
using static Microsoft.Azure.Cosmos.Internal.RntbdConstants;
|
||||
using static Microsoft.Azure.Cosmos.Routing.PartitionRoutingHelper;
|
||||
using static Microsoft.Azure.Documents.RntbdConstants;
|
||||
|
||||
/// <summary>
|
||||
/// Handler which manages the continution token and partion-key-range-id selection depending on a provided start and end epk and direction.
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
namespace Microsoft.Azure.Cosmos.Handlers
|
||||
{
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Documents;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Threading;
|
||||
|
@ -39,7 +40,7 @@ namespace Microsoft.Azure.Cosmos.Handlers
|
|||
|
||||
// Validate the request consistency compatibility with account consistency
|
||||
// Type based access context for requested consistency preferred for performance
|
||||
ConsistencyLevel? consistencyLevel = null;
|
||||
Cosmos.ConsistencyLevel? consistencyLevel = null;
|
||||
if (promotedRequestOptions is CosmosItemRequestOptions)
|
||||
{
|
||||
consistencyLevel = (promotedRequestOptions as CosmosItemRequestOptions).ConsistencyLevel;
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace Microsoft.Azure.Cosmos.Handlers
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Documents;
|
||||
|
||||
/// <summary>
|
||||
/// Handler which selects the piepline for the requested resource operation
|
||||
|
|
|
@ -9,6 +9,7 @@ namespace Microsoft.Azure.Cosmos.Handlers
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Documents;
|
||||
|
||||
//TODO: write unit test for this handler
|
||||
internal class TransportHandler : CosmosRequestHandler
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.Azure.Cosmos.Collections;
|
||||
using Microsoft.Azure.Documents.Collections;
|
||||
|
||||
/// <summary>
|
||||
/// Internal header class with priority access for known headers and support for dictionary-based access to other headers.
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Documents;
|
||||
|
||||
/// <summary>
|
||||
/// Http headers in a <see cref="CosmosRequestMessage"/>.
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Documents;
|
||||
|
||||
/// <summary>
|
||||
/// HTTP headers in a <see cref="CosmosResponseMessage"/>.
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -7,6 +7,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Documents;
|
||||
|
||||
internal interface IRetryPolicyFactory
|
||||
{
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
//------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------
|
||||
|
||||
namespace Microsoft.Azure.Cosmos
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface exposed for mocking purposes for the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
internal interface IDocumentResponse<TDocument> : IResourceResponseBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the document returned in the response.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The document returned in the response.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// This is exposed for mocking purposes for the Azure Cosmos DB service.
|
||||
/// </remarks>
|
||||
TDocument Document { get; }
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
namespace Microsoft.Azure.Cosmos
|
||||
{
|
||||
using Microsoft.Azure.Cosmos.Collections;
|
||||
using Microsoft.Azure.Documents.Collections;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
|
|
@ -8,6 +8,7 @@ namespace Microsoft.Azure.Cosmos.Common
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Documents;
|
||||
|
||||
internal interface IRequestSigner
|
||||
{
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
//------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------
|
||||
|
||||
namespace Microsoft.Azure.Cosmos
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface exposed for mocking purposes for the Azure Cosmos DB service.
|
||||
/// </summary>
|
||||
/// <typeparam name="TResource">The resource type.</typeparam>
|
||||
internal interface IResourceResponse<TResource> : IResourceResponseBase where TResource : CosmosResource, new()
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the resource returned in the response.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The resource returned in the response.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// This is exposed for mocking purposes for the Azure Cosmos DB service.
|
||||
/// </remarks>
|
||||
TResource Resource { get; }
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Documents;
|
||||
|
||||
internal sealed class IndexingPolicyBuilder
|
||||
{
|
||||
|
|
|
@ -0,0 +1,168 @@
|
|||
//-----------------------------------------------------------------------
|
||||
// <copyright file="ByteOrder.cs" company="Microsoft Corporation">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
namespace Microsoft.Azure.Cosmos.Json
|
||||
{
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// The ByteOrder class is capable of reversing the bytes of any primitive type.
|
||||
/// </summary>
|
||||
internal static class ByteOrder
|
||||
{
|
||||
/// <summary>
|
||||
/// Reverses a single byte.
|
||||
/// </summary>
|
||||
/// <param name="value">The byte to reverse</param>
|
||||
/// <returns>The reversed byte.</returns>
|
||||
/// <remarks>Since a single byte has no byte order, so the value itself is returned so this is essentially a NO-OP.</remarks>
|
||||
public static byte Reverse(byte value)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reverses a bool.
|
||||
/// </summary>
|
||||
/// <param name="value">The bool to reverse</param>
|
||||
/// <returns>The reversed bool.</returns>
|
||||
/// <remarks>Since a bool has no byte order, so the value itself is returned so this is essentially a NO-OP.</remarks>
|
||||
public static bool Reverse(bool value)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reverses a char.
|
||||
/// </summary>
|
||||
/// <param name="value">The char to reverse.</param>
|
||||
/// <returns>The reversed char.</returns>
|
||||
public static char Reverse(char value)
|
||||
{
|
||||
ushort b1 = (ushort)(((ushort)value >> 0) & 0xff);
|
||||
ushort b2 = (ushort)(((ushort)value >> 8) & 0xff);
|
||||
|
||||
return (char)(b1 << 8 | b2 << 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reverses a short.
|
||||
/// </summary>
|
||||
/// <param name="value">The short to reverse.</param>
|
||||
/// <returns>The reversed short.</returns>
|
||||
public static short Reverse(short value)
|
||||
{
|
||||
ushort b1 = (ushort)(((ushort)value >> 0) & 0xff);
|
||||
ushort b2 = (ushort)(((ushort)value >> 8) & 0xff);
|
||||
|
||||
return (short)(b1 << 8 | b2 << 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reverses a ushort.
|
||||
/// </summary>
|
||||
/// <param name="value">The ushort to reverse.</param>
|
||||
/// <returns>The reversed ushort.</returns>
|
||||
public static ushort Reverse(ushort value)
|
||||
{
|
||||
ushort b1 = (ushort)((value >> 0) & 0xff);
|
||||
ushort b2 = (ushort)((value >> 8) & 0xff);
|
||||
|
||||
return (ushort)(b1 << 8 | b2 << 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reverses a int.
|
||||
/// </summary>
|
||||
/// <param name="value">The int to reverse.</param>
|
||||
/// <returns>The reversed int.</returns>
|
||||
public static int Reverse(int value)
|
||||
{
|
||||
uint b1 = ((uint)value >> 0) & 0xff;
|
||||
uint b2 = ((uint)value >> 8) & 0xff;
|
||||
uint b3 = ((uint)value >> 16) & 0xff;
|
||||
uint b4 = ((uint)value >> 24) & 0xff;
|
||||
|
||||
return (int)(b1 << 24 | b2 << 16 | b3 << 8 | b4 << 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reverses a uint.
|
||||
/// </summary>
|
||||
/// <param name="value">The uint to reverse.</param>
|
||||
/// <returns>The reversed uint.</returns>
|
||||
public static uint Reverse(uint value)
|
||||
{
|
||||
uint b1 = (value >> 0) & 0xff;
|
||||
uint b2 = (value >> 8) & 0xff;
|
||||
uint b3 = (value >> 16) & 0xff;
|
||||
uint b4 = (value >> 24) & 0xff;
|
||||
|
||||
return b1 << 24 | b2 << 16 | b3 << 8 | b4 << 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reverses a long.
|
||||
/// </summary>
|
||||
/// <param name="value">The long to reverse.</param>
|
||||
/// <returns>The reversed long.</returns>
|
||||
public static long Reverse(long value)
|
||||
{
|
||||
ulong b1 = ((ulong)value >> 0) & 0xff;
|
||||
ulong b2 = ((ulong)value >> 8) & 0xff;
|
||||
ulong b3 = ((ulong)value >> 16) & 0xff;
|
||||
ulong b4 = ((ulong)value >> 24) & 0xff;
|
||||
ulong b5 = ((ulong)value >> 32) & 0xff;
|
||||
ulong b6 = ((ulong)value >> 40) & 0xff;
|
||||
ulong b7 = ((ulong)value >> 48) & 0xff;
|
||||
ulong b8 = ((ulong)value >> 56) & 0xff;
|
||||
|
||||
return (long)(b1 << 56 | b2 << 48 | b3 << 40 | b4 << 32 | b5 << 24 | b6 << 16 | b7 << 8 | b8 << 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reverses a ulong.
|
||||
/// </summary>
|
||||
/// <param name="value">The ulong to reverse.</param>
|
||||
/// <returns>The reversed ulong.</returns>
|
||||
public static ulong Reverse(ulong value)
|
||||
{
|
||||
ulong b1 = (value >> 0) & 0xff;
|
||||
ulong b2 = (value >> 8) & 0xff;
|
||||
ulong b3 = (value >> 16) & 0xff;
|
||||
ulong b4 = (value >> 24) & 0xff;
|
||||
ulong b5 = (value >> 32) & 0xff;
|
||||
ulong b6 = (value >> 40) & 0xff;
|
||||
ulong b7 = (value >> 48) & 0xff;
|
||||
ulong b8 = (value >> 56) & 0xff;
|
||||
|
||||
return b1 << 56 | b2 << 48 | b3 << 40 | b4 << 32 | b5 << 24 | b6 << 16 | b7 << 8 | b8 << 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reverses a float.
|
||||
/// </summary>
|
||||
/// <param name="value">The float to reverse.</param>
|
||||
/// <returns>The reversed float.</returns>
|
||||
public static float Reverse(float value)
|
||||
{
|
||||
byte[] floatAsBytes = BitConverter.GetBytes(value);
|
||||
Array.Reverse(floatAsBytes);
|
||||
return BitConverter.ToSingle(floatAsBytes, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reverses a double.
|
||||
/// </summary>
|
||||
/// <param name="value">The double to reverse.</param>
|
||||
/// <returns>The reversed double.</returns>
|
||||
public static double Reverse(double value)
|
||||
{
|
||||
byte[] doubleAsBytes = BitConverter.GetBytes(value);
|
||||
Array.Reverse(doubleAsBytes);
|
||||
return BitConverter.ToDouble(doubleAsBytes, 0);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
//-----------------------------------------------------------------------
|
||||
// <copyright file="IJsonNavigator.cs" company="Microsoft Corporation">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
namespace Microsoft.Azure.Cosmos.Json
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// JsonNavigator interface for classes that can navigate jsons.
|
||||
/// </summary>
|
||||
internal interface IJsonNavigator
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the <see cref="JsonSerializationFormat"/> for the IJsonNavigator.
|
||||
/// </summary>
|
||||
JsonSerializationFormat SerializationFormat { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets <see cref="IJsonNavigatorNode"/> of the root node.
|
||||
/// </summary>
|
||||
/// <returns><see cref="IJsonNavigatorNode"/> corresponding to the root node.</returns>
|
||||
IJsonNavigatorNode GetRootNode();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="JsonNodeType"/> type for a particular node
|
||||
/// </summary>
|
||||
/// <param name="node">The <see cref="IJsonNavigatorNode"/> of the node you want to know the type of</param>
|
||||
/// <returns><see cref="JsonNodeType"/> for the node</returns>
|
||||
JsonNodeType GetNodeType(IJsonNavigatorNode node);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the numeric value for a node
|
||||
/// </summary>
|
||||
/// <param name="numberNode">The <see cref="IJsonNavigatorNode"/> of the node you want the number value from.</param>
|
||||
/// <returns>A double that represents the number value in the node.</returns>
|
||||
double GetNumberValue(IJsonNavigatorNode numberNode);
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the buffered string value from a node.
|
||||
/// </summary>
|
||||
/// <param name="stringNode">The <see cref="IJsonNavigatorNode"/> of the node to get the buffered string from.</param>
|
||||
/// <param name="bufferedStringValue">The buffered string value if possible</param>
|
||||
/// <returns><code>true</code> if the JsonNavigator successfully got the buffered string value; <code>false</code> if the JsonNavigator failed to get the buffered string value.</returns>
|
||||
bool TryGetBufferedStringValue(IJsonNavigatorNode stringNode, out IReadOnlyList<byte> bufferedStringValue);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a string value from a node.
|
||||
/// </summary>
|
||||
/// <param name="stringNode">The <see cref="IJsonNavigatorNode"/> of the node to get the string value from.</param>
|
||||
/// <returns>The string value from the node.</returns>
|
||||
string GetStringValue(IJsonNavigatorNode stringNode);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of elements in an array node.
|
||||
/// </summary>
|
||||
/// <param name="arrayNode">The <see cref="IJsonNavigatorNode"/> of the (array) node to get the count of.</param>
|
||||
/// <returns>The number of elements in the array node.</returns>
|
||||
int GetArrayItemCount(IJsonNavigatorNode arrayNode);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the node at a particular index of an array node
|
||||
/// </summary>
|
||||
/// <param name="arrayNode">The <see cref="IJsonNavigatorNode"/> of the (array) node to index from.</param>
|
||||
/// <param name="index">The offset into the array</param>
|
||||
/// <returns>The <see cref="IJsonNavigatorNode"/> of the node at a particular index of an array node</returns>
|
||||
IJsonNavigatorNode GetArrayItemAt(IJsonNavigatorNode arrayNode, int index);
|
||||
|
||||
/// <summary>
|
||||
/// Gets an IEnumerable of <see cref="IJsonNavigatorNode"/>s for an arrayNode.
|
||||
/// </summary>
|
||||
/// <param name="arrayNode">The <see cref="IJsonNavigatorNode"/> of the array to get the items from</param>
|
||||
/// <returns>The IEnumerable of <see cref="IJsonNavigatorNode"/>s for an arrayNode.</returns>
|
||||
IEnumerable<IJsonNavigatorNode> GetArrayItems(IJsonNavigatorNode arrayNode);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of properties in an object node.
|
||||
/// </summary>
|
||||
/// <param name="objectNode">The <see cref="IJsonNavigatorNode"/> of node to get the property count from.</param>
|
||||
/// <returns>The number of properties in an object node.</returns>
|
||||
int GetObjectPropertyCount(IJsonNavigatorNode objectNode);
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get a object property from an object with a particular property name.
|
||||
/// </summary>
|
||||
/// <param name="objectNode">The <see cref="IJsonNavigatorNode"/> of object node to get a property from.</param>
|
||||
/// <param name="propertyName">The name of the property to search for.</param>
|
||||
/// <param name="objectProperty">The <see cref="ObjectProperty"/> with the specified property name if it exists.</param>
|
||||
/// <returns><code>true</code> if the JsonNavigator successfully found the <see cref="IJsonNavigatorNode"/> with the specified property name; <code>false</code> otherwise.</returns>
|
||||
bool TryGetObjectProperty(IJsonNavigatorNode objectNode, string propertyName, out ObjectProperty objectProperty);
|
||||
|
||||
/// <summary>
|
||||
/// Gets an IEnumerable of <see cref="ObjectProperty"/> properties from an object node.
|
||||
/// </summary>
|
||||
/// <param name="objectNode">The <see cref="IJsonNavigatorNode"/> of object node to get the properties from.</param>
|
||||
/// <returns>The IEnumerable of <see cref="ObjectProperty"/> properties from an object node.</returns>
|
||||
IEnumerable<ObjectProperty> GetObjectProperties(IJsonNavigatorNode objectNode);
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the buffered raw json
|
||||
/// </summary>
|
||||
/// <param name="jsonNode">The json node of interest</param>
|
||||
/// <param name="bufferedRawJson">The raw json.</param>
|
||||
/// <returns>True if bufferedRawJson was set. False otherwise.</returns>
|
||||
bool TryGetBufferedRawJson(IJsonNavigatorNode jsonNode, out IReadOnlyList<byte> bufferedRawJson);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
//-----------------------------------------------------------------------
|
||||
// <copyright file="IJsonNavigatorNode.cs" company="Microsoft Corporation">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
namespace Microsoft.Azure.Cosmos.Json
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface that describes a Node within a JSON document in a <see cref="IJsonNavigator"/>
|
||||
/// </summary>
|
||||
internal interface IJsonNavigatorNode
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
//-----------------------------------------------------------------------
|
||||
// <copyright file="IJsonReader.cs" company="Microsoft Corporation">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
namespace Microsoft.Azure.Cosmos.Json
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Interface for all JsonReaders that know how to read jsons.
|
||||
/// </summary>
|
||||
internal interface IJsonReader
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the <see cref="JsonSerializationFormat"/> for the JsonReader
|
||||
/// </summary>
|
||||
JsonSerializationFormat SerializationFormat { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current level of nesting of the JSON that the JsonReader is reading.
|
||||
/// </summary>
|
||||
int CurrentDepth { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="JsonTokenType"/> of the current token that the JsonReader is about to read.
|
||||
/// </summary>
|
||||
JsonTokenType CurrentTokenType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Advances the JsonReader by one token.
|
||||
/// </summary>
|
||||
/// <returns><code>true</code> if the JsonReader successfully advanced to the next token; <code>false</code> if the JsonReader has passed the end of the JSON.</returns>
|
||||
bool Read();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the next JSON token from the JsonReader as a double.
|
||||
/// </summary>
|
||||
/// <returns>The next JSON token from the JsonReader as a double.</returns>
|
||||
double GetNumberValue();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the next JSON token from the JsonReader as a string.
|
||||
/// </summary>
|
||||
/// <returns>The next JSON token from the JsonReader as a string.</returns>
|
||||
string GetStringValue();
|
||||
|
||||
/// <summary>
|
||||
/// Gets current JSON token from the JsonReader as a raw series of bytes that is buffered.
|
||||
/// </summary>
|
||||
/// <returns>The current JSON token from the JsonReader as a raw series of bytes that is buffered.</returns>
|
||||
IReadOnlyList<byte> GetBufferedRawJsonToken();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
//-----------------------------------------------------------------------
|
||||
// <copyright file="IJsonWriter.cs" company="Microsoft Corporation">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
namespace Microsoft.Azure.Cosmos.Json
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Interface for all JsonWriters that know how to write jsons of a specific serialization format.
|
||||
/// </summary>
|
||||
internal interface IJsonWriter
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the SerializationFormat of the JsonWriter.
|
||||
/// </summary>
|
||||
JsonSerializationFormat SerializationFormat { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current length of the internal buffer.
|
||||
/// </summary>
|
||||
long CurrentLength { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Writes the object start symbol to internal buffer.
|
||||
/// </summary>
|
||||
void WriteObjectStart();
|
||||
|
||||
/// <summary>
|
||||
/// Writes the object end symbol to the internal buffer.
|
||||
/// </summary>
|
||||
void WriteObjectEnd();
|
||||
|
||||
/// <summary>
|
||||
/// Writes the array start symbol to the internal buffer.
|
||||
/// </summary>
|
||||
void WriteArrayStart();
|
||||
|
||||
/// <summary>
|
||||
/// Writes the array end symbol to the internal buffer.
|
||||
/// </summary>
|
||||
void WriteArrayEnd();
|
||||
|
||||
/// <summary>
|
||||
/// Writes a field name to the the internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="fieldName">The name of the field to write.</param>
|
||||
void WriteFieldName(string fieldName);
|
||||
|
||||
/// <summary>
|
||||
/// Writes a string to the internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="value">The value of the string to write.</param>
|
||||
void WriteStringValue(string value);
|
||||
|
||||
/// <summary>
|
||||
/// Writes an integer to the internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="value">The value of the integer to write.</param>
|
||||
void WriteIntValue(long value);
|
||||
|
||||
/// <summary>
|
||||
/// Writes a number to the internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="value">The value of the number to write.</param>
|
||||
void WriteNumberValue(double value);
|
||||
|
||||
/// <summary>
|
||||
/// Writes a boolean to the internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="value">The value of the boolean to write.</param>
|
||||
void WriteBoolValue(bool value);
|
||||
|
||||
/// <summary>
|
||||
/// Writes a null to the internal buffer.
|
||||
/// </summary>
|
||||
void WriteNullValue();
|
||||
|
||||
/// <summary>
|
||||
/// Writes current token from a json reader to the internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="jsonReader">The JsonReader to the get the current token from.</param>
|
||||
void WriteCurrentToken(IJsonReader jsonReader);
|
||||
|
||||
/// <summary>
|
||||
/// Writes every token from the JsonReader to the internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="jsonReader">The JsonReader to get the tokens from.</param>
|
||||
void WriteAll(IJsonReader jsonReader);
|
||||
|
||||
/// <summary>
|
||||
/// Writes a fragment of a json to the internal buffer
|
||||
/// </summary>
|
||||
/// <param name="jsonFragment">A section of a valid json</param>
|
||||
void WriteJsonFragment(IReadOnlyList<byte> jsonFragment);
|
||||
|
||||
/// <summary>
|
||||
/// Writes a json node to the internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="jsonNavigator">The navigator to use to navigate the node</param>
|
||||
/// <param name="jsonNavigatorNode">The node to write.</param>
|
||||
void WriteJsonNode(IJsonNavigator jsonNavigator, IJsonNavigatorNode jsonNavigatorNode);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the result of the JsonWriter.
|
||||
/// </summary>
|
||||
/// <returns>The result of the JsonWriter as an array of bytes.</returns>
|
||||
byte[] GetResult();
|
||||
}
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,261 @@
|
|||
//-----------------------------------------------------------------------
|
||||
// <copyright file="NewtonsoftReader.cs" company="Microsoft Corporation">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
namespace Microsoft.Azure.Cosmos.Json
|
||||
{
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
/// <summary>
|
||||
/// Wrapper class that implements a Newtonsoft JsonReader,
|
||||
/// but forwards all the calls to a CosmosDB JSON reader.
|
||||
/// </summary>
|
||||
internal sealed class JsonCosmosDBReader : Newtonsoft.Json.JsonReader
|
||||
{
|
||||
/// <summary>
|
||||
/// Singleton boxed value for null.
|
||||
/// </summary>
|
||||
private static readonly object Null = null;
|
||||
|
||||
/// <summary>
|
||||
/// Singleton boxed value for false.
|
||||
/// </summary>
|
||||
private static readonly object False = false;
|
||||
|
||||
/// <summary>
|
||||
/// Singleton boxed value for true.
|
||||
/// </summary>
|
||||
private static readonly object True = true;
|
||||
|
||||
/// <summary>
|
||||
/// The CosmosDB JSON Reader that will be used for implementation.
|
||||
/// </summary>
|
||||
private readonly IJsonReader jsonReader;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the NewtonsoftReader class.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to read from.</param>
|
||||
public JsonCosmosDBReader(Stream stream)
|
||||
{
|
||||
this.jsonReader = JsonReader.Create(stream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the next token from the reader.
|
||||
/// </summary>
|
||||
/// <returns>True if a token was read, else false.</returns>
|
||||
public override bool Read()
|
||||
{
|
||||
bool read = this.jsonReader.Read();
|
||||
if (!read)
|
||||
{
|
||||
this.SetToken(JsonToken.None);
|
||||
return false;
|
||||
}
|
||||
|
||||
JsonTokenType jsonTokenType = this.jsonReader.CurrentTokenType;
|
||||
JsonToken newtonsoftToken;
|
||||
object value;
|
||||
switch (jsonTokenType)
|
||||
{
|
||||
case JsonTokenType.BeginArray:
|
||||
newtonsoftToken = JsonToken.StartArray;
|
||||
value = JsonCosmosDBReader.Null;
|
||||
break;
|
||||
|
||||
case JsonTokenType.EndArray:
|
||||
newtonsoftToken = JsonToken.EndArray;
|
||||
value = JsonCosmosDBReader.Null;
|
||||
break;
|
||||
|
||||
case JsonTokenType.BeginObject:
|
||||
newtonsoftToken = JsonToken.StartObject;
|
||||
value = JsonCosmosDBReader.Null;
|
||||
break;
|
||||
|
||||
case JsonTokenType.EndObject:
|
||||
newtonsoftToken = JsonToken.EndObject;
|
||||
value = JsonCosmosDBReader.Null;
|
||||
break;
|
||||
|
||||
case JsonTokenType.String:
|
||||
newtonsoftToken = JsonToken.String;
|
||||
value = this.jsonReader.GetStringValue();
|
||||
break;
|
||||
|
||||
case JsonTokenType.Number:
|
||||
value = this.jsonReader.GetNumberValue();
|
||||
if ((double)value % 1 == 0)
|
||||
{
|
||||
newtonsoftToken = JsonToken.Integer;
|
||||
}
|
||||
else
|
||||
{
|
||||
newtonsoftToken = JsonToken.Float;
|
||||
}
|
||||
break;
|
||||
|
||||
case JsonTokenType.True:
|
||||
newtonsoftToken = JsonToken.Boolean;
|
||||
value = JsonCosmosDBReader.True;
|
||||
break;
|
||||
|
||||
case JsonTokenType.False:
|
||||
newtonsoftToken = JsonToken.Boolean;
|
||||
value = JsonCosmosDBReader.False;
|
||||
break;
|
||||
|
||||
case JsonTokenType.Null:
|
||||
newtonsoftToken = JsonToken.Null;
|
||||
value = JsonCosmosDBReader.Null;
|
||||
break;
|
||||
|
||||
case JsonTokenType.FieldName:
|
||||
newtonsoftToken = JsonToken.PropertyName;
|
||||
value = this.jsonReader.GetStringValue();
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentException($"Unexpected jsonTokenType: {jsonTokenType}");
|
||||
}
|
||||
|
||||
this.SetToken(newtonsoftToken, value);
|
||||
return read;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the next JSON token from the source as a <see cref="Byte"/>[].
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="Byte"/>[] or <c>null</c> if the next JSON token is null. This method will return <c>null</c> at the end of an array.</returns>
|
||||
public override byte[] ReadAsBytes()
|
||||
{
|
||||
this.Read();
|
||||
byte[] value = this.jsonReader.GetBufferedRawJsonToken().ToArray();
|
||||
this.SetToken(JsonToken.Bytes, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the next JSON token from the source as a <see cref="Nullable{T}"/> of <see cref="DateTime"/>.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="Nullable{T}"/> of <see cref="DateTime"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
public override DateTime? ReadAsDateTime()
|
||||
{
|
||||
DateTime? dateTime = (DateTime?)this.ReadAsTypeFromString<DateTime>(DateTime.Parse);
|
||||
if (dateTime != null)
|
||||
{
|
||||
this.SetToken(JsonToken.Date, dateTime);
|
||||
}
|
||||
|
||||
return dateTime;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the next JSON token from the source as a <see cref="Nullable{T}"/> of <see cref="DateTimeOffset"/>.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="Nullable{T}"/> of <see cref="DateTimeOffset"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
public override DateTimeOffset? ReadAsDateTimeOffset()
|
||||
{
|
||||
DateTimeOffset? dateTimeOffset = (DateTimeOffset?)this.ReadAsTypeFromString<DateTimeOffset>(DateTimeOffset.Parse);
|
||||
if (dateTimeOffset != null)
|
||||
{
|
||||
this.SetToken(JsonToken.Date, dateTimeOffset);
|
||||
}
|
||||
|
||||
return dateTimeOffset;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the next JSON token from the source as a <see cref="Nullable{T}"/> of <see cref="Decimal"/>.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="Nullable{T}"/> of <see cref="Decimal"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
public override decimal? ReadAsDecimal()
|
||||
{
|
||||
decimal? value = (decimal?)this.ReadNumberValue();
|
||||
if (value != null)
|
||||
{
|
||||
this.SetToken(JsonToken.Float, value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the next JSON token from the source as a <see cref="Nullable{T}"/> of <see cref="Int32"/>.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="Nullable{T}"/> of <see cref="Int32"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
public override int? ReadAsInt32()
|
||||
{
|
||||
int? value = (int?)this.ReadNumberValue();
|
||||
if (value != null)
|
||||
{
|
||||
this.SetToken(JsonToken.Integer, value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the next JSON token from the source as a <see cref="String"/>.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="String"/>. This method will return <c>null</c> at the end of an array.</returns>
|
||||
public override string ReadAsString()
|
||||
{
|
||||
string value = (string)this.ReadAsTypeFromString<string>((x) => x);
|
||||
if (value != null)
|
||||
{
|
||||
this.SetToken(JsonToken.String, value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the next string token and deserializes it to a type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type to deserialize to.</typeparam>
|
||||
/// <param name="parse">The function that deserializes the token.</param>
|
||||
/// <returns>The next string token deserialized to a type or null if at the end of an array.</returns>
|
||||
private object ReadAsTypeFromString<T>(Func<string, T> parse)
|
||||
{
|
||||
this.Read();
|
||||
object value;
|
||||
if (this.jsonReader.CurrentTokenType == JsonTokenType.EndArray)
|
||||
{
|
||||
value = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
string stringValue = this.jsonReader.GetStringValue();
|
||||
value = parse(stringValue);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the next number token but returns null at the end of an array.
|
||||
/// </summary>
|
||||
/// <returns>The next number token but returns null at the end of an array.</returns>
|
||||
private double? ReadNumberValue()
|
||||
{
|
||||
this.Read();
|
||||
double? value;
|
||||
if (this.jsonReader.CurrentTokenType == JsonTokenType.EndArray)
|
||||
{
|
||||
value = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = this.jsonReader.GetNumberValue();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,377 @@
|
|||
//-----------------------------------------------------------------------
|
||||
// <copyright file="NewtonsoftWriter.cs" company="Microsoft Corporation">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
namespace Microsoft.Azure.Cosmos.Json
|
||||
{
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
/// <summary>
|
||||
/// Wrapper class that implements Newtonsoft's JsonWriter,
|
||||
/// but calls into a CosmosDB JsonWriter for the implementation.
|
||||
/// </summary>
|
||||
internal sealed class JsonCosmosDBWriter : Newtonsoft.Json.JsonWriter
|
||||
{
|
||||
/// <summary>
|
||||
/// A CosmosDB JSON writer used for the actual implementation.
|
||||
/// </summary>
|
||||
private readonly IJsonWriter jsonWriter;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the NewtonsoftWriter class.
|
||||
/// </summary>
|
||||
/// <param name="jsonSerializationFormat">The SerializationFormat to use.</param>
|
||||
public JsonCosmosDBWriter(JsonSerializationFormat jsonSerializationFormat)
|
||||
{
|
||||
this.jsonWriter = JsonWriter.Create(jsonSerializationFormat);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flushes whatever is in the buffer to the underlying <see cref="Stream"/> and also flushes the underlying stream.
|
||||
/// </summary>
|
||||
public override void Flush()
|
||||
{
|
||||
this.jsonWriter.GetResult();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a comment <c>/*...*/</c> containing the specified text.
|
||||
/// </summary>
|
||||
/// <param name="text">Text to place inside the comment.</param>
|
||||
public override void WriteComment(string text)
|
||||
{
|
||||
throw new NotSupportedException("Cannot write JSON comment.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the end of an array.
|
||||
/// </summary>
|
||||
public override void WriteEndArray()
|
||||
{
|
||||
base.WriteEndArray();
|
||||
this.jsonWriter.WriteArrayEnd();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the end constructor.
|
||||
/// </summary>
|
||||
public override void WriteEndConstructor()
|
||||
{
|
||||
throw new NotSupportedException("Cannot write end constructor.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the end of a JSON object.
|
||||
/// </summary>
|
||||
public override void WriteEndObject()
|
||||
{
|
||||
base.WriteEndObject();
|
||||
this.jsonWriter.WriteObjectEnd();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a null value.
|
||||
/// </summary>
|
||||
public override void WriteNull()
|
||||
{
|
||||
base.WriteNull();
|
||||
this.jsonWriter.WriteNullValue();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the property name of a name/value pair on a JSON object.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the property.</param>
|
||||
public override void WritePropertyName(string name)
|
||||
{
|
||||
this.WritePropertyName(name, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the property name of a name/value pair on a JSON object.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the property.</param>
|
||||
/// <param name="escape">Whether or not to escape the name</param>
|
||||
public override void WritePropertyName(string name, bool escape)
|
||||
{
|
||||
base.WritePropertyName(name);
|
||||
this.jsonWriter.WriteFieldName(name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the start of a constructor with the given name.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the constructor.</param>
|
||||
public override void WriteStartConstructor(string name)
|
||||
{
|
||||
throw new NotSupportedException("Cannot write Start constructor.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes raw JSON.
|
||||
/// </summary>
|
||||
/// <param name="json">The raw JSON to write.</param>
|
||||
public override void WriteRaw(string json)
|
||||
{
|
||||
IJsonReader jsonReader = JsonReader.Create(Encoding.UTF8.GetBytes(json));
|
||||
this.jsonWriter.WriteAll(jsonReader);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes raw JSON where a value is expected and updates the writer's state.
|
||||
/// </summary>
|
||||
/// <param name="json">The raw JSON to write.</param>
|
||||
public override void WriteRawValue(string json)
|
||||
{
|
||||
IJsonReader jsonReader = JsonReader.Create(Encoding.UTF8.GetBytes(json));
|
||||
this.jsonWriter.WriteAll(jsonReader);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the beginning of a JSON array.
|
||||
/// </summary>
|
||||
public override void WriteStartArray()
|
||||
{
|
||||
base.WriteStartArray();
|
||||
this.jsonWriter.WriteArrayStart();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the beginning of a JSON object.
|
||||
/// </summary>
|
||||
public override void WriteStartObject()
|
||||
{
|
||||
base.WriteStartObject();
|
||||
this.jsonWriter.WriteObjectStart();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes an undefined value.
|
||||
/// </summary>
|
||||
public override void WriteUndefined()
|
||||
{
|
||||
throw new NotSupportedException("Can not write undefined");
|
||||
}
|
||||
|
||||
#region WriteValue methods
|
||||
/// <summary>
|
||||
/// Writes a <see cref="Object"/> value.
|
||||
/// An error will raised if the value cannot be written as a single JSON token.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Object"/> value to write.</param>
|
||||
public override void WriteValue(object value)
|
||||
{
|
||||
if (value is string)
|
||||
{
|
||||
this.WriteValue((string)value);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.WriteValue((double)value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="String"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="String"/> value to write.</param>
|
||||
public override void WriteValue(string value)
|
||||
{
|
||||
base.WriteValue(value);
|
||||
this.jsonWriter.WriteStringValue(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="Int32"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Int32"/> value to write.</param>
|
||||
public override void WriteValue(int value)
|
||||
{
|
||||
this.WriteValue((long)value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="UInt32"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="UInt32"/> value to write.</param>
|
||||
public override void WriteValue(uint value)
|
||||
{
|
||||
this.WriteValue((long)value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="Int64"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Int64"/> value to write.</param>
|
||||
public override void WriteValue(long value)
|
||||
{
|
||||
base.WriteValue(value);
|
||||
this.jsonWriter.WriteIntValue(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="UInt64"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="UInt64"/> value to write.</param>
|
||||
public override void WriteValue(ulong value)
|
||||
{
|
||||
if(value <= long.MaxValue)
|
||||
{
|
||||
this.WriteValue((long)value);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.WriteValue((double)value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="Single"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Single"/> value to write.</param>
|
||||
public override void WriteValue(float value)
|
||||
{
|
||||
this.WriteValue((double)value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="Double"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Double"/> value to write.</param>
|
||||
public override void WriteValue(double value)
|
||||
{
|
||||
base.WriteValue(value);
|
||||
this.jsonWriter.WriteNumberValue(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="Boolean"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Boolean"/> value to write.</param>
|
||||
public override void WriteValue(bool value)
|
||||
{
|
||||
base.WriteValue(value);
|
||||
this.jsonWriter.WriteBoolValue(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="Int16"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Int16"/> value to write.</param>
|
||||
public override void WriteValue(short value)
|
||||
{
|
||||
base.WriteValue((long)value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="UInt16"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="UInt16"/> value to write.</param>
|
||||
public override void WriteValue(ushort value)
|
||||
{
|
||||
this.WriteValue((long)value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="Char"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Char"/> value to write.</param>
|
||||
public override void WriteValue(char value)
|
||||
{
|
||||
base.WriteValue(value);
|
||||
this.jsonWriter.WriteStringValue(value.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="Byte"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Byte"/> value to write.</param>
|
||||
public override void WriteValue(byte value)
|
||||
{
|
||||
this.WriteValue((long)value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="SByte"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="SByte"/> value to write.</param>
|
||||
public override void WriteValue(sbyte value)
|
||||
{
|
||||
this.WriteValue((long)value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="Decimal"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Decimal"/> value to write.</param>
|
||||
public override void WriteValue(decimal value)
|
||||
{
|
||||
this.WriteValue((double)value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="DateTime"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="DateTime"/> value to write.</param>
|
||||
public override void WriteValue(DateTime value)
|
||||
{
|
||||
this.WriteValue(value.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="Byte"/>[] value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Byte"/>[] value to write.</param>
|
||||
public override void WriteValue(byte[] value)
|
||||
{
|
||||
throw new NotSupportedException("Can not write byte arrays");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="Guid"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Guid"/> value to write.</param>
|
||||
public override void WriteValue(Guid value)
|
||||
{
|
||||
this.WriteValue(value.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="TimeSpan"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="TimeSpan"/> value to write.</param>
|
||||
public override void WriteValue(TimeSpan value)
|
||||
{
|
||||
this.WriteValue(value.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="Uri"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Uri"/> value to write.</param>
|
||||
public override void WriteValue(Uri value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
this.WriteNull();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.WriteValue(value.ToString());
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Gets the result of all the tokens written so far.
|
||||
/// </summary>
|
||||
/// <returns>The result of all the tokens written so far.</returns>
|
||||
public byte[] GetResult()
|
||||
{
|
||||
return this.jsonWriter.GetResult();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,473 @@
|
|||
//-----------------------------------------------------------------------
|
||||
// <copyright file="JsonNavigator.JsonBinaryNavigator.cs" company="Microsoft Corporation">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
namespace Microsoft.Azure.Cosmos.Json
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
/// <summary>
|
||||
/// Partial class that wraps the private JsonTextNavigator
|
||||
/// </summary>
|
||||
internal abstract partial class JsonNavigator : IJsonNavigator
|
||||
{
|
||||
/// <summary>
|
||||
/// JsonNavigator that know how to navigate JSONs in binary serialization.
|
||||
/// </summary>
|
||||
private sealed class JsonBinaryNavigator : JsonNavigator
|
||||
{
|
||||
private readonly BinaryNode rootNode;
|
||||
private readonly LittleEndianBinaryReader binaryReader;
|
||||
private readonly byte[] buffer;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonBinaryNavigator class
|
||||
/// </summary>
|
||||
/// <param name="buffer">The (UTF-8) buffer to navigate.</param>
|
||||
/// <param name="skipValidation">whether to skip validation or not.</param>
|
||||
public JsonBinaryNavigator(byte[] buffer, bool skipValidation = false)
|
||||
{
|
||||
if (buffer == null)
|
||||
{
|
||||
throw new ArgumentNullException($"{nameof(buffer)} can not be null");
|
||||
}
|
||||
|
||||
if(buffer.Length < 1)
|
||||
{
|
||||
throw new ArgumentException($"{nameof(buffer)} must have at least one byte.");
|
||||
}
|
||||
|
||||
this.rootNode = new BinaryNode(1, JsonBinaryEncoding.GetNodeType(buffer[1]));
|
||||
|
||||
// false, since stream is not writeable
|
||||
// true, since buffer is visible
|
||||
this.binaryReader = new LittleEndianBinaryReader(new MemoryStream(buffer, 0, buffer.Length, false, true));
|
||||
this.buffer = buffer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="JsonSerializationFormat"/> for the IJsonNavigator.
|
||||
/// </summary>
|
||||
public override JsonSerializationFormat SerializationFormat
|
||||
{
|
||||
get
|
||||
{
|
||||
return JsonSerializationFormat.Binary;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets <see cref="IJsonNavigatorNode"/> of the root node.
|
||||
/// </summary>
|
||||
/// <returns><see cref="IJsonNavigatorNode"/> corresponding to the root node.</returns>
|
||||
public override IJsonNavigatorNode GetRootNode()
|
||||
{
|
||||
return this.rootNode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="JsonNodeType"/> type for a particular node
|
||||
/// </summary>
|
||||
/// <param name="node">The <see cref="IJsonNavigatorNode"/> of the node you want to know the type of</param>
|
||||
/// <returns><see cref="JsonNodeType"/> for the node</returns>
|
||||
public override JsonNodeType GetNodeType(IJsonNavigatorNode node)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(node));
|
||||
}
|
||||
|
||||
if ((node as BinaryNode) == null)
|
||||
{
|
||||
throw new ArgumentException($"{nameof(node)} must be a binary node.");
|
||||
}
|
||||
|
||||
return ((BinaryNode)node).JsonNodeType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the numeric value for a node
|
||||
/// </summary>
|
||||
/// <param name="numberNavigatorNode">The <see cref="IJsonNavigatorNode"/> of the node you want the number value from.</param>
|
||||
/// <returns>A double that represents the number value in the node.</returns>
|
||||
public override double GetNumberValue(IJsonNavigatorNode numberNavigatorNode)
|
||||
{
|
||||
if (numberNavigatorNode == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(numberNavigatorNode));
|
||||
}
|
||||
|
||||
if (!(((numberNavigatorNode as BinaryNode)?.JsonNodeType ?? JsonNodeType.Unknown) == JsonNodeType.Number))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(numberNavigatorNode)} must be a binary number node.");
|
||||
}
|
||||
|
||||
long offset = ((BinaryNode)numberNavigatorNode).Offset;
|
||||
this.binaryReader.BaseStream.Seek(offset, SeekOrigin.Begin);
|
||||
return JsonBinaryEncoding.GetNumberValue(this.binaryReader);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the buffered string value from a node.
|
||||
/// </summary>
|
||||
/// <param name="stringNode">The <see cref="IJsonNavigatorNode"/> of the node to get the buffered string from.</param>
|
||||
/// <param name="bufferedStringValue">The buffered string value if possible</param>
|
||||
/// <returns><code>true</code> if the JsonNavigator successfully got the buffered string value; <code>false</code> if the JsonNavigator failed to get the buffered string value.</returns>
|
||||
public override bool TryGetBufferedStringValue(IJsonNavigatorNode stringNode, out IReadOnlyList<byte> bufferedStringValue)
|
||||
{
|
||||
//TODO (brchon): implement this when optimizing code.
|
||||
bufferedStringValue = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a string value from a node.
|
||||
/// </summary>
|
||||
/// <param name="stringNode">The <see cref="IJsonNavigatorNode"/> of the node to get the string value from.</param>
|
||||
/// <returns>The string value from the node.</returns>
|
||||
public override string GetStringValue(IJsonNavigatorNode stringNode)
|
||||
{
|
||||
if (stringNode == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(stringNode));
|
||||
}
|
||||
|
||||
if (!((((stringNode as BinaryNode)?.JsonNodeType ?? JsonNodeType.Unknown) == JsonNodeType.String) ||
|
||||
(((stringNode as BinaryNode)?.JsonNodeType ?? JsonNodeType.Unknown) == JsonNodeType.FieldName)))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(stringNode)} must be a binary string or fieldname node.");
|
||||
}
|
||||
|
||||
long offset = ((BinaryNode)stringNode).Offset;
|
||||
this.binaryReader.BaseStream.Seek(offset, SeekOrigin.Begin);
|
||||
return JsonBinaryEncoding.GetStringValue(this.binaryReader);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of elements in an array node.
|
||||
/// </summary>
|
||||
/// <param name="arrayNavigatorNode">The <see cref="IJsonNavigatorNode"/> of the (array) node to get the count of.</param>
|
||||
/// <returns>The number of elements in the array node.</returns>
|
||||
public override int GetArrayItemCount(IJsonNavigatorNode arrayNavigatorNode)
|
||||
{
|
||||
if (arrayNavigatorNode == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(arrayNavigatorNode));
|
||||
}
|
||||
|
||||
if (!(((arrayNavigatorNode as BinaryNode)?.JsonNodeType ?? JsonNodeType.Unknown) == JsonNodeType.Array))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(arrayNavigatorNode)} must be a binary array node.");
|
||||
}
|
||||
|
||||
int offset = ((BinaryNode)arrayNavigatorNode).Offset;
|
||||
byte typeMarker = this.buffer[offset];
|
||||
int firstValueOffset = offset + JsonBinaryEncoding.GetFirstValueOffset(typeMarker);
|
||||
long count;
|
||||
switch (typeMarker)
|
||||
{
|
||||
// Empty and Single Array
|
||||
case JsonBinaryEncoding.TypeMarker.EmptyArray:
|
||||
count = 0;
|
||||
break;
|
||||
case JsonBinaryEncoding.TypeMarker.SingleItemArray:
|
||||
count = 1;
|
||||
break;
|
||||
|
||||
// Arrays with length and count prefix
|
||||
case JsonBinaryEncoding.TypeMarker.Array1ByteLengthAndCount:
|
||||
count = this.buffer[offset + JsonBinaryEncoding.TypeMarkerLength + JsonBinaryEncoding.OneByteLength];
|
||||
break;
|
||||
case JsonBinaryEncoding.TypeMarker.Array2ByteLengthAndCount:
|
||||
count = BitConverter.ToUInt16(this.buffer, offset + JsonBinaryEncoding.TypeMarkerLength + JsonBinaryEncoding.TwoByteLength);
|
||||
break;
|
||||
case JsonBinaryEncoding.TypeMarker.Array4ByteLengthAndCount:
|
||||
count = BitConverter.ToUInt32(this.buffer, offset + JsonBinaryEncoding.TypeMarkerLength + JsonBinaryEncoding.FourByteLength);
|
||||
break;
|
||||
|
||||
// Arrays with length prefix
|
||||
case JsonBinaryEncoding.TypeMarker.Array1ByteLength:
|
||||
count = this.GetValueCount(firstValueOffset, this.buffer[offset + JsonBinaryEncoding.TypeMarkerLength]);
|
||||
break;
|
||||
case JsonBinaryEncoding.TypeMarker.Array2ByteLength:
|
||||
count = this.GetValueCount(firstValueOffset, BitConverter.ToUInt16(this.buffer, offset + JsonBinaryEncoding.TypeMarkerLength));
|
||||
break;
|
||||
case JsonBinaryEncoding.TypeMarker.Array4ByteLength:
|
||||
count = this.GetValueCount(firstValueOffset, BitConverter.ToUInt32(this.buffer, offset + JsonBinaryEncoding.TypeMarkerLength));
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException($"Unexpected array type marker: {typeMarker}");
|
||||
}
|
||||
|
||||
if (count > int.MaxValue)
|
||||
{
|
||||
throw new InvalidOperationException("count can not be more than int.MaxValue");
|
||||
}
|
||||
|
||||
return (int)count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the node at a particular index of an array node
|
||||
/// </summary>
|
||||
/// <param name="arrayNavigatorNode">The <see cref="IJsonNavigatorNode"/> of the (array) node to index from.</param>
|
||||
/// <param name="index">The offset into the array</param>
|
||||
/// <returns>The <see cref="IJsonNavigatorNode"/> of the node at a particular index of an array node</returns>
|
||||
public override IJsonNavigatorNode GetArrayItemAt(IJsonNavigatorNode arrayNavigatorNode, int index)
|
||||
{
|
||||
if (arrayNavigatorNode == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(arrayNavigatorNode));
|
||||
}
|
||||
|
||||
if (!(((arrayNavigatorNode as BinaryNode)?.JsonNodeType ?? JsonNodeType.Unknown) == JsonNodeType.Array))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(arrayNavigatorNode)} must be a binary array node.");
|
||||
}
|
||||
|
||||
// TODO (brchon): We can optimize for the case where the count is serialized so we can avoid using the linear time call to TryGetValueAt().
|
||||
|
||||
int arrayOffset = ((BinaryNode)arrayNavigatorNode).Offset;
|
||||
byte typeMarker = this.buffer[arrayOffset];
|
||||
|
||||
BinaryNode node;
|
||||
long firstArrayItemOffset = arrayOffset + JsonBinaryEncoding.GetFirstValueOffset(typeMarker);
|
||||
long arrayLength = JsonBinaryEncoding.GetValueLength(this.buffer, arrayOffset);
|
||||
long arrayItemsLength = arrayLength - (firstArrayItemOffset - arrayOffset);
|
||||
if (!this.TryGetValueAt(firstArrayItemOffset, arrayItemsLength, index, out node))
|
||||
{
|
||||
throw new IndexOutOfRangeException($"Tried to access index:{index} in an array.");
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an IEnumerable of <see cref="IJsonNavigatorNode"/>s for an arrayNode.
|
||||
/// </summary>
|
||||
/// <param name="arrayNavigatorNode">The <see cref="IJsonNavigatorNode"/> of the array to get the items from</param>
|
||||
/// <returns>The IEnumerable of <see cref="IJsonNavigatorNode"/>s for an arrayNode.</returns>
|
||||
public override IEnumerable<IJsonNavigatorNode> GetArrayItems(IJsonNavigatorNode arrayNavigatorNode)
|
||||
{
|
||||
if (arrayNavigatorNode == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(arrayNavigatorNode));
|
||||
}
|
||||
|
||||
if (!(((arrayNavigatorNode as BinaryNode)?.JsonNodeType ?? JsonNodeType.Unknown) == JsonNodeType.Array))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(arrayNavigatorNode)} must be a binary array node.");
|
||||
}
|
||||
|
||||
int arrayOffset = ((BinaryNode)arrayNavigatorNode).Offset;
|
||||
byte typeMarker = this.buffer[arrayOffset];
|
||||
|
||||
long arrayLength = JsonBinaryEncoding.GetValueLength(this.buffer, arrayOffset);
|
||||
long firstValueOffset = arrayOffset + JsonBinaryEncoding.GetFirstValueOffset(typeMarker);
|
||||
long bytesToProcess = (arrayOffset + arrayLength) - firstValueOffset;
|
||||
|
||||
for (int bytesProcessed = 0; bytesProcessed < bytesToProcess; bytesProcessed += (int)JsonBinaryEncoding.GetValueLength(this.buffer, firstValueOffset + bytesProcessed))
|
||||
{
|
||||
yield return this.CreateBinaryNode((int)(firstValueOffset + bytesProcessed));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of properties in an object node.
|
||||
/// </summary>
|
||||
/// <param name="objectNavigatorNode">The <see cref="IJsonNavigatorNode"/> of node to get the property count from.</param>
|
||||
/// <returns>The number of properties in an object node.</returns>
|
||||
public override int GetObjectPropertyCount(IJsonNavigatorNode objectNavigatorNode)
|
||||
{
|
||||
if (objectNavigatorNode == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(objectNavigatorNode));
|
||||
}
|
||||
|
||||
if (!(((objectNavigatorNode as BinaryNode)?.JsonNodeType ?? JsonNodeType.Unknown) == JsonNodeType.Object))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(objectNavigatorNode)} must be a binary object node.");
|
||||
}
|
||||
|
||||
int objectOffset = ((BinaryNode)objectNavigatorNode).Offset;
|
||||
byte typeMarker = this.buffer[objectOffset];
|
||||
int firstObjectPropertyOffset = objectOffset + JsonBinaryEncoding.GetFirstValueOffset(typeMarker);
|
||||
long count;
|
||||
switch (typeMarker)
|
||||
{
|
||||
// Empty and Single Object
|
||||
case JsonBinaryEncoding.TypeMarker.EmptyObject:
|
||||
count = 0;
|
||||
break;
|
||||
case JsonBinaryEncoding.TypeMarker.SinglePropertyObject:
|
||||
// This number gets divided by 2 later.
|
||||
count = 2;
|
||||
break;
|
||||
|
||||
// Object with length and count prefix
|
||||
case JsonBinaryEncoding.TypeMarker.Object1ByteLengthAndCount:
|
||||
count = this.buffer[objectOffset + JsonBinaryEncoding.TypeMarkerLength + JsonBinaryEncoding.OneByteLength];
|
||||
break;
|
||||
case JsonBinaryEncoding.TypeMarker.Object2ByteLengthAndCount:
|
||||
count = BitConverter.ToUInt16(this.buffer, objectOffset + JsonBinaryEncoding.TypeMarkerLength + JsonBinaryEncoding.TwoByteLength);
|
||||
break;
|
||||
case JsonBinaryEncoding.TypeMarker.Object4ByteLengthAndCount:
|
||||
count = BitConverter.ToUInt32(this.buffer, objectOffset + JsonBinaryEncoding.TypeMarkerLength + JsonBinaryEncoding.FourByteLength);
|
||||
break;
|
||||
|
||||
// Object with length prefix
|
||||
case JsonBinaryEncoding.TypeMarker.Object1ByteLength:
|
||||
count = this.GetValueCount(firstObjectPropertyOffset, this.buffer[objectOffset + JsonBinaryEncoding.TypeMarkerLength]);
|
||||
break;
|
||||
case JsonBinaryEncoding.TypeMarker.Object2ByteLength:
|
||||
count = this.GetValueCount(firstObjectPropertyOffset, BitConverter.ToUInt16(this.buffer, objectOffset + JsonBinaryEncoding.TypeMarkerLength));
|
||||
break;
|
||||
case JsonBinaryEncoding.TypeMarker.Object4ByteLength:
|
||||
count = this.GetValueCount(firstObjectPropertyOffset, BitConverter.ToUInt32(this.buffer, objectOffset + JsonBinaryEncoding.TypeMarkerLength));
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException($"Unexpected object type marker: {typeMarker}");
|
||||
}
|
||||
|
||||
// Divide by 2 since the count includes fieldname and value as seperate entities
|
||||
count = count / 2;
|
||||
if (count > int.MaxValue)
|
||||
{
|
||||
throw new InvalidOperationException("count can not be more than int.MaxValue");
|
||||
}
|
||||
|
||||
return (int)count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get a object property from an object with a particular property name.
|
||||
/// </summary>
|
||||
/// <param name="objectNavigatorNode">The <see cref="ObjectProperty"/> of object node to get a property from.</param>
|
||||
/// <param name="propertyName">The name of the property to search for.</param>
|
||||
/// <param name="objectProperty">The <see cref="IJsonNavigatorNode"/> with the specified property name if it exists.</param>
|
||||
/// <returns><code>true</code> if the JsonNavigator successfully found the <see cref="ObjectProperty"/> with the specified property name; <code>false</code> otherwise.</returns>
|
||||
public override bool TryGetObjectProperty(IJsonNavigatorNode objectNavigatorNode, string propertyName, out ObjectProperty objectProperty)
|
||||
{
|
||||
foreach (ObjectProperty objectPropertyNode in this.GetObjectProperties(objectNavigatorNode))
|
||||
{
|
||||
if (this.GetStringValue(objectPropertyNode.NameNode) == propertyName)
|
||||
{
|
||||
objectProperty = objectPropertyNode;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
objectProperty = default(ObjectProperty);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an IEnumerable of <see cref="IJsonNavigatorNode"/> properties from an object node.
|
||||
/// </summary>
|
||||
/// <param name="objectNavigatorNode">The <see cref="IJsonNavigatorNode"/> of object node to get the properties from.</param>
|
||||
/// <returns>The IEnumerable of <see cref="IJsonNavigatorNode"/> properties from an object node.</returns>
|
||||
public override IEnumerable<ObjectProperty> GetObjectProperties(IJsonNavigatorNode objectNavigatorNode)
|
||||
{
|
||||
if (objectNavigatorNode == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(objectNavigatorNode));
|
||||
}
|
||||
|
||||
if (!(((objectNavigatorNode as BinaryNode)?.JsonNodeType ?? JsonNodeType.Unknown) == JsonNodeType.Object))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(objectNavigatorNode)} must actually be a binary object node.");
|
||||
}
|
||||
|
||||
int offset = ((BinaryNode)objectNavigatorNode).Offset;
|
||||
byte typeMarker = this.buffer[offset];
|
||||
long objectLength = JsonBinaryEncoding.GetValueLength(this.buffer, offset);
|
||||
long firstValueOffset = offset + JsonBinaryEncoding.GetFirstValueOffset(typeMarker);
|
||||
long bytesToProcess = (offset + objectLength) - firstValueOffset;
|
||||
for (int bytesProcessed = 0; bytesProcessed < bytesToProcess;)
|
||||
{
|
||||
BinaryNode nameNode = new BinaryNode((int)(firstValueOffset + bytesProcessed), JsonNodeType.FieldName);
|
||||
bytesProcessed += (int)JsonBinaryEncoding.GetValueLength(this.buffer, firstValueOffset + bytesProcessed);
|
||||
BinaryNode valueNode = this.CreateBinaryNode((int)(firstValueOffset + bytesProcessed));
|
||||
bytesProcessed += (int)JsonBinaryEncoding.GetValueLength(this.buffer, firstValueOffset + bytesProcessed);
|
||||
yield return new ObjectProperty(nameNode, valueNode);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the buffered raw json
|
||||
/// </summary>
|
||||
/// <param name="jsonNode">The json node of interest</param>
|
||||
/// <param name="bufferedRawJson">The raw json.</param>
|
||||
/// <returns>True if bufferedRawJson was set. False otherwise.</returns>
|
||||
public override bool TryGetBufferedRawJson(IJsonNavigatorNode jsonNode, out IReadOnlyList<byte> bufferedRawJson)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private int GetValueCount(long offset, long length)
|
||||
{
|
||||
long bytesProcessed = 0;
|
||||
int count = 0;
|
||||
while (bytesProcessed < length)
|
||||
{
|
||||
count++;
|
||||
bytesProcessed += JsonBinaryEncoding.GetValueLength(this.buffer, offset + bytesProcessed);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
private bool TryGetValueAt(long offset, long length, long index, out BinaryNode node)
|
||||
{
|
||||
long currentOffset = offset;
|
||||
for (long count = 0; count < index; count++)
|
||||
{
|
||||
long valueLength = JsonBinaryEncoding.GetValueLength(this.buffer, currentOffset);
|
||||
if (valueLength == 0)
|
||||
{
|
||||
node = default(BinaryNode);
|
||||
return false;
|
||||
}
|
||||
|
||||
currentOffset += valueLength;
|
||||
if (currentOffset >= (offset + length))
|
||||
{
|
||||
node = default(BinaryNode);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentOffset > int.MaxValue)
|
||||
{
|
||||
throw new InvalidOperationException($"{nameof(currentOffset)} is greater than int.MaxValue");
|
||||
}
|
||||
|
||||
node = this.CreateBinaryNode((int)currentOffset);
|
||||
return true;
|
||||
}
|
||||
|
||||
private BinaryNode CreateBinaryNode(int offset)
|
||||
{
|
||||
return new BinaryNode(offset, JsonBinaryEncoding.GetNodeType(this.buffer[offset]));
|
||||
}
|
||||
|
||||
private class BinaryNode : IJsonNavigatorNode
|
||||
{
|
||||
public BinaryNode(int offset, JsonNodeType jsonNodeType)
|
||||
{
|
||||
this.Offset = offset;
|
||||
this.JsonNodeType = jsonNodeType;
|
||||
}
|
||||
|
||||
public int Offset { get; }
|
||||
|
||||
public JsonNodeType JsonNodeType { get; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,752 @@
|
|||
//-----------------------------------------------------------------------
|
||||
// <copyright file="JsonNavigator.JsonTextNavigator.cs" company="Microsoft Corporation">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
namespace Microsoft.Azure.Cosmos.Json
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Partial class that wraps the private JsonTextNavigator
|
||||
/// </summary>
|
||||
internal abstract partial class JsonNavigator : IJsonNavigator
|
||||
{
|
||||
/// <summary>
|
||||
/// JsonNavigator that know how to navigate JSONs in text serialization.
|
||||
/// Internally the navigator uses a <see cref="JsonTextParser"/> to from an AST of the JSON and the rest of the methods are just letting you traverse the materialized tree.
|
||||
/// </summary>
|
||||
private sealed class JsonTextNavigator : JsonNavigator
|
||||
{
|
||||
private readonly JsonTextNode rootNode;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonTextNavigator class
|
||||
/// </summary>
|
||||
/// <param name="buffer">The (UTF-8) buffer to navigate.</param>
|
||||
/// <param name="skipValidation">whether to skip validation or not.</param>
|
||||
public JsonTextNavigator(byte[] buffer, bool skipValidation = false)
|
||||
{
|
||||
IJsonReader jsonTextReader = JsonReader.Create(buffer, skipValidation);
|
||||
if (jsonTextReader.SerializationFormat != JsonSerializationFormat.Text)
|
||||
{
|
||||
throw new ArgumentException("jsonTextReader's serialization format must actually be text");
|
||||
}
|
||||
|
||||
this.rootNode = JsonTextParser.Parse(jsonTextReader);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="JsonSerializationFormat"/> for the IJsonNavigator.
|
||||
/// </summary>
|
||||
public override JsonSerializationFormat SerializationFormat
|
||||
{
|
||||
get
|
||||
{
|
||||
return JsonSerializationFormat.Text;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets <see cref="IJsonNavigatorNode"/> of the root node.
|
||||
/// </summary>
|
||||
/// <returns><see cref="IJsonNavigatorNode"/> corresponding to the root node.</returns>
|
||||
public override IJsonNavigatorNode GetRootNode()
|
||||
{
|
||||
return this.rootNode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="JsonNodeType"/> type for a particular node
|
||||
/// </summary>
|
||||
/// <param name="node">The <see cref="IJsonNavigatorNode"/> of the node you want to know the type of</param>
|
||||
/// <returns><see cref="JsonNodeType"/> for the node</returns>
|
||||
public override JsonNodeType GetNodeType(IJsonNavigatorNode node)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
throw new ArgumentNullException("node");
|
||||
}
|
||||
|
||||
JsonTextNode jsonTextNode = node as JsonTextNode;
|
||||
if (jsonTextNode == null)
|
||||
{
|
||||
throw new ArgumentException("node must actually be a text node.");
|
||||
}
|
||||
|
||||
return jsonTextNode.JsonNodeType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the numeric value for a node
|
||||
/// </summary>
|
||||
/// <param name="numberNavigatorNode">The <see cref="IJsonNavigatorNode"/> of the node you want the number value from.</param>
|
||||
/// <returns>A double that represents the number value in the node.</returns>
|
||||
public override double GetNumberValue(IJsonNavigatorNode numberNavigatorNode)
|
||||
{
|
||||
if (numberNavigatorNode == null)
|
||||
{
|
||||
throw new ArgumentNullException("numberNavigatorNode");
|
||||
}
|
||||
|
||||
NumberNode numberNode = numberNavigatorNode as NumberNode;
|
||||
if (numberNode == null)
|
||||
{
|
||||
throw new ArgumentException("numberNavigatorNode must actually be a number node.");
|
||||
}
|
||||
|
||||
return numberNode.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the buffered string value from a node.
|
||||
/// </summary>
|
||||
/// <param name="stringNode">The <see cref="IJsonNavigatorNode"/> of the node to get the buffered string from.</param>
|
||||
/// <param name="bufferedStringValue">The buffered string value if possible</param>
|
||||
/// <returns><code>true</code> if the JsonNavigator successfully got the buffered string value; <code>false</code> if the JsonNavigator failed to get the buffered string value.</returns>
|
||||
public override bool TryGetBufferedStringValue(IJsonNavigatorNode stringNode, out IReadOnlyList<byte> bufferedStringValue)
|
||||
{
|
||||
bufferedStringValue = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a string value from a node.
|
||||
/// </summary>
|
||||
/// <param name="stringNode">The <see cref="IJsonNavigatorNode"/> of the node to get the string value from.</param>
|
||||
/// <returns>The string value from the node.</returns>
|
||||
public override string GetStringValue(IJsonNavigatorNode stringNode)
|
||||
{
|
||||
if (stringNode == null)
|
||||
{
|
||||
throw new ArgumentNullException("stringNode");
|
||||
}
|
||||
|
||||
StringNodeBase stringValueNode = stringNode as StringNodeBase;
|
||||
if (stringValueNode == null)
|
||||
{
|
||||
throw new ArgumentException("stringNode must actually be a number node.");
|
||||
}
|
||||
|
||||
return stringValueNode.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of elements in an array node.
|
||||
/// </summary>
|
||||
/// <param name="arrayNavigatorNode">The <see cref="IJsonNavigatorNode"/> of the (array) node to get the count of.</param>
|
||||
/// <returns>The number of elements in the array node.</returns>
|
||||
public override int GetArrayItemCount(IJsonNavigatorNode arrayNavigatorNode)
|
||||
{
|
||||
if (arrayNavigatorNode == null)
|
||||
{
|
||||
throw new ArgumentNullException("arrayNavigatorNode");
|
||||
}
|
||||
|
||||
ArrayNode arrayNode = arrayNavigatorNode as ArrayNode;
|
||||
if (arrayNode == null)
|
||||
{
|
||||
throw new ArgumentException("arrayNavigatorNode must actually be an array node");
|
||||
}
|
||||
|
||||
return arrayNode.Items.Count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the node at a particular index of an array node
|
||||
/// </summary>
|
||||
/// <param name="arrayNavigatorNode">The <see cref="IJsonNavigatorNode"/> of the (array) node to index from.</param>
|
||||
/// <param name="index">The offset into the array</param>
|
||||
/// <returns>The <see cref="IJsonNavigatorNode"/> of the node at a particular index of an array node</returns>
|
||||
public override IJsonNavigatorNode GetArrayItemAt(IJsonNavigatorNode arrayNavigatorNode, int index)
|
||||
{
|
||||
if (arrayNavigatorNode == null)
|
||||
{
|
||||
throw new ArgumentNullException("arrayNode");
|
||||
}
|
||||
|
||||
ArrayNode arrayNode = arrayNavigatorNode as ArrayNode;
|
||||
if (arrayNode == null)
|
||||
{
|
||||
throw new ArgumentException("arrayNavigatorNode must actually be an array node");
|
||||
}
|
||||
|
||||
return arrayNode.Items[index];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an IEnumerable of <see cref="IJsonNavigatorNode"/>s for an arrayNode.
|
||||
/// </summary>
|
||||
/// <param name="arrayNavigatorNode">The <see cref="IJsonNavigatorNode"/> of the array to get the items from</param>
|
||||
/// <returns>The IEnumerable of <see cref="IJsonNavigatorNode"/>s for an arrayNode.</returns>
|
||||
public override IEnumerable<IJsonNavigatorNode> GetArrayItems(IJsonNavigatorNode arrayNavigatorNode)
|
||||
{
|
||||
if (arrayNavigatorNode == null)
|
||||
{
|
||||
throw new ArgumentNullException("arrayNode");
|
||||
}
|
||||
|
||||
ArrayNode arrayNode = arrayNavigatorNode as ArrayNode;
|
||||
if (arrayNode == null)
|
||||
{
|
||||
throw new ArgumentException("arrayNavigatorNode must actually be an array node");
|
||||
}
|
||||
|
||||
return arrayNode.Items;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of properties in an object node.
|
||||
/// </summary>
|
||||
/// <param name="objectNavigatorNode">The <see cref="IJsonNavigatorNode"/> of node to get the property count from.</param>
|
||||
/// <returns>The number of properties in an object node.</returns>
|
||||
public override int GetObjectPropertyCount(IJsonNavigatorNode objectNavigatorNode)
|
||||
{
|
||||
if (objectNavigatorNode == null)
|
||||
{
|
||||
throw new ArgumentNullException("objectNode");
|
||||
}
|
||||
|
||||
ObjectNode objectNode = objectNavigatorNode as ObjectNode;
|
||||
if (objectNode == null)
|
||||
{
|
||||
throw new ArgumentException("objectNavigatorNode must actually be an array node");
|
||||
}
|
||||
|
||||
return objectNode.Properties.Count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get a object property from an object with a particular property name.
|
||||
/// </summary>
|
||||
/// <param name="objectNavigatorNode">The <see cref="ObjectProperty"/> of object node to get a property from.</param>
|
||||
/// <param name="propertyName">The name of the property to search for.</param>
|
||||
/// <param name="objectProperty">The <see cref="IJsonNavigatorNode"/> with the specified property name if it exists.</param>
|
||||
/// <returns><code>true</code> if the JsonNavigator successfully found the <see cref="ObjectProperty"/> with the specified property name; <code>false</code> otherwise.</returns>
|
||||
public override bool TryGetObjectProperty(IJsonNavigatorNode objectNavigatorNode, string propertyName, out ObjectProperty objectProperty)
|
||||
{
|
||||
if (objectNavigatorNode == null)
|
||||
{
|
||||
throw new ArgumentNullException("objectNavigatorNode");
|
||||
}
|
||||
|
||||
if (propertyName == null)
|
||||
{
|
||||
throw new ArgumentNullException("propertyName");
|
||||
}
|
||||
|
||||
ObjectNode objectNode = objectNavigatorNode as ObjectNode;
|
||||
if (objectNode == null)
|
||||
{
|
||||
throw new ArgumentException("objectNavigatorNode must actually be an array node");
|
||||
}
|
||||
|
||||
objectProperty = default(ObjectProperty);
|
||||
IReadOnlyList<ObjectProperty> properties = ((ObjectNode)objectNode).Properties;
|
||||
foreach (ObjectProperty property in properties)
|
||||
{
|
||||
if (this.GetStringValue(property.NameNode) == propertyName)
|
||||
{
|
||||
objectProperty = property;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an IEnumerable of <see cref="IJsonNavigatorNode"/> properties from an object node.
|
||||
/// </summary>
|
||||
/// <param name="objectNavigatorNode">The <see cref="IJsonNavigatorNode"/> of object node to get the properties from.</param>
|
||||
/// <returns>The IEnumerable of <see cref="IJsonNavigatorNode"/> properties from an object node.</returns>
|
||||
public override IEnumerable<ObjectProperty> GetObjectProperties(IJsonNavigatorNode objectNavigatorNode)
|
||||
{
|
||||
if (objectNavigatorNode == null)
|
||||
{
|
||||
throw new ArgumentNullException("objectNode");
|
||||
}
|
||||
|
||||
ObjectNode objectNode = objectNavigatorNode as ObjectNode;
|
||||
if (objectNode == null)
|
||||
{
|
||||
throw new ArgumentException("objectNavigatorNode must actually be an array node");
|
||||
}
|
||||
|
||||
return objectNode.Properties;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the buffered raw json
|
||||
/// </summary>
|
||||
/// <param name="jsonNode">The json node of interest</param>
|
||||
/// <param name="bufferedRawJson">The raw json.</param>
|
||||
/// <returns>True if bufferedRawJson was set. False otherwise.</returns>
|
||||
public override bool TryGetBufferedRawJson(IJsonNavigatorNode jsonNode, out IReadOnlyList<byte> bufferedRawJson)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
#region JsonTextParser
|
||||
/// <summary>
|
||||
/// The JsonTextParser class is used to get a JSON AST / DOM from plaintext using a JsonTextReader as a lexer / tokenizer.
|
||||
/// Internally the parser is implemented as an LL(1) parser, since JSON is unambiguous and we can just parse it using recursive decent.
|
||||
/// </summary>
|
||||
private static class JsonTextParser
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the root node of a JSON AST from a jsonTextReader.
|
||||
/// </summary>
|
||||
/// <param name="jsonTextReader">The reader to use as a lexer / tokenizer</param>
|
||||
/// <returns>The root node of a JSON AST from a jsonTextReader.</returns>
|
||||
public static JsonTextNode Parse(IJsonReader jsonTextReader)
|
||||
{
|
||||
if (jsonTextReader.SerializationFormat != JsonSerializationFormat.Text)
|
||||
{
|
||||
throw new ArgumentException("jsonTextReader's serialization format must actually be text");
|
||||
}
|
||||
|
||||
// Read past the json object not started state.
|
||||
jsonTextReader.Read();
|
||||
|
||||
JsonTextNode rootNode = JsonTextParser.ParseNode(jsonTextReader);
|
||||
|
||||
// Make sure that we are at the end of the file.
|
||||
if (jsonTextReader.Read())
|
||||
{
|
||||
throw new ArgumentException("Did not fully parse json");
|
||||
}
|
||||
|
||||
return rootNode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses out a JSON array AST node with a jsonTextReader.
|
||||
/// </summary>
|
||||
/// <param name="jsonTextReader">The reader to use as a lexer / tokenizer</param>
|
||||
/// <returns>JSON array AST node</returns>
|
||||
private static ArrayNode ParseArrayNode(IJsonReader jsonTextReader)
|
||||
{
|
||||
List<JsonTextNode> items = new List<JsonTextNode>();
|
||||
|
||||
// consume the begin array token
|
||||
jsonTextReader.Read();
|
||||
|
||||
while (jsonTextReader.CurrentTokenType != JsonTokenType.EndArray)
|
||||
{
|
||||
items.Add(JsonTextParser.ParseNode(jsonTextReader));
|
||||
}
|
||||
|
||||
// consume the end array token
|
||||
jsonTextReader.Read();
|
||||
|
||||
return ArrayNode.Create(items);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses out a JSON object AST node with a jsonTextReader.
|
||||
/// </summary>
|
||||
/// <param name="jsonTextReader">The reader to use as a lexer / tokenizer</param>
|
||||
/// <returns>JSON object AST node</returns>
|
||||
private static ObjectNode ParseObjectNode(IJsonReader jsonTextReader)
|
||||
{
|
||||
List<ObjectProperty> properties = new List<ObjectProperty>();
|
||||
|
||||
// consume the begin object token
|
||||
jsonTextReader.Read();
|
||||
|
||||
while (jsonTextReader.CurrentTokenType != JsonTokenType.EndObject)
|
||||
{
|
||||
ObjectProperty property = JsonTextParser.ParsePropertyNode(jsonTextReader);
|
||||
properties.Add(property);
|
||||
}
|
||||
|
||||
// consume the end object token
|
||||
jsonTextReader.Read();
|
||||
|
||||
return ObjectNode.Create(properties);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses out a JSON string AST node with a jsonTextReader.
|
||||
/// </summary>
|
||||
/// <param name="jsonTextReader">The reader to use as a lexer / tokenizer</param>
|
||||
/// <returns>JSON string AST node</returns>
|
||||
private static StringNode ParseStringNode(IJsonReader jsonTextReader)
|
||||
{
|
||||
StringNode stringNode = StringNode.Create((ArraySegment<byte>)jsonTextReader.GetBufferedRawJsonToken());
|
||||
|
||||
// consume the string from the reader
|
||||
jsonTextReader.Read();
|
||||
|
||||
return stringNode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses out a JSON number AST node with a jsonTextReader.
|
||||
/// </summary>
|
||||
/// <param name="jsonTextReader">The reader to use as a lexer / tokenizer</param>
|
||||
/// <returns>JSON number AST node</returns>
|
||||
private static NumberNode ParseNumberNode(IJsonReader jsonTextReader)
|
||||
{
|
||||
NumberNode numberNode = NumberNode.Create((ArraySegment<byte>)jsonTextReader.GetBufferedRawJsonToken());
|
||||
|
||||
// consume the number from the reader
|
||||
jsonTextReader.Read();
|
||||
|
||||
return numberNode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses out a JSON true AST node with a jsonTextReader.
|
||||
/// </summary>
|
||||
/// <param name="jsonTextReader">The reader to use as a lexer / tokenizer</param>
|
||||
/// <returns>JSON true AST node</returns>
|
||||
private static TrueNode ParseTrueNode(IJsonReader jsonTextReader)
|
||||
{
|
||||
// consume the true token from the reader
|
||||
jsonTextReader.Read();
|
||||
|
||||
return TrueNode.Create();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses out a JSON false AST node with a jsonTextReader.
|
||||
/// </summary>
|
||||
/// <param name="jsonTextReader">The reader to use as a lexer / tokenizer</param>
|
||||
/// <returns>JSON true AST node</returns>
|
||||
private static FalseNode ParseFalseNode(IJsonReader jsonTextReader)
|
||||
{
|
||||
// consume the false token from the reader
|
||||
jsonTextReader.Read();
|
||||
|
||||
return FalseNode.Create();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses out a JSON null AST node with a jsonTextReader.
|
||||
/// </summary>
|
||||
/// <param name="jsonTextReader">The reader to use as a lexer / tokenizer</param>
|
||||
/// <returns>JSON null AST node</returns>
|
||||
private static NullNode ParseNullNode(IJsonReader jsonTextReader)
|
||||
{
|
||||
// consume the null token from the reader
|
||||
jsonTextReader.Read();
|
||||
|
||||
return NullNode.Create();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses out a JSON property AST node with a jsonTextReader.
|
||||
/// </summary>
|
||||
/// <param name="jsonTextReader">The reader to use as a lexer / tokenizer</param>
|
||||
/// <returns>JSON property AST node</returns>
|
||||
private static ObjectProperty ParsePropertyNode(IJsonReader jsonTextReader)
|
||||
{
|
||||
FieldNameNode fieldName = FieldNameNode.Create((ArraySegment<byte>)jsonTextReader.GetBufferedRawJsonToken());
|
||||
|
||||
// Consume the fieldname from the jsonreader
|
||||
jsonTextReader.Read();
|
||||
|
||||
JsonTextNode value = JsonTextParser.ParseNode(jsonTextReader);
|
||||
return new ObjectProperty(fieldName, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses out a JSON AST node with a jsonTextReader.
|
||||
/// </summary>
|
||||
/// <param name="jsonTextReader">The reader to use as a lexer / tokenizer</param>
|
||||
/// <returns>JSON AST node (type determined by the reader)</returns>
|
||||
private static JsonTextNode ParseNode(IJsonReader jsonTextReader)
|
||||
{
|
||||
JsonTextNode node;
|
||||
switch (jsonTextReader.CurrentTokenType)
|
||||
{
|
||||
case JsonTokenType.BeginArray:
|
||||
node = JsonTextParser.ParseArrayNode(jsonTextReader);
|
||||
break;
|
||||
case JsonTokenType.BeginObject:
|
||||
node = JsonTextParser.ParseObjectNode(jsonTextReader);
|
||||
break;
|
||||
case JsonTokenType.String:
|
||||
node = JsonTextParser.ParseStringNode(jsonTextReader);
|
||||
break;
|
||||
case JsonTokenType.Number:
|
||||
node = JsonTextParser.ParseNumberNode(jsonTextReader);
|
||||
break;
|
||||
case JsonTokenType.True:
|
||||
node = JsonTextParser.ParseTrueNode(jsonTextReader);
|
||||
break;
|
||||
case JsonTokenType.False:
|
||||
node = JsonTextParser.ParseFalseNode(jsonTextReader);
|
||||
break;
|
||||
case JsonTokenType.Null:
|
||||
node = JsonTextParser.ParseNullNode(jsonTextReader);
|
||||
break;
|
||||
default:
|
||||
throw new JsonInvalidTokenException();
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Nodes
|
||||
private sealed class ArrayNode : JsonTextNode
|
||||
{
|
||||
private static readonly ArrayNode Empty = new ArrayNode(new List<JsonTextNode>());
|
||||
private readonly List<JsonTextNode> items;
|
||||
|
||||
private ArrayNode(List<JsonTextNode> items)
|
||||
: base(JsonNodeType.Array)
|
||||
{
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
public IReadOnlyList<JsonTextNode> Items
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.items;
|
||||
}
|
||||
}
|
||||
|
||||
public static ArrayNode Create(List<JsonTextNode> items)
|
||||
{
|
||||
if (items.Count == 0)
|
||||
{
|
||||
return ArrayNode.Empty;
|
||||
}
|
||||
|
||||
return new ArrayNode(items);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class FalseNode : JsonTextNode
|
||||
{
|
||||
private static readonly FalseNode Instance = new FalseNode();
|
||||
|
||||
private FalseNode()
|
||||
: base(JsonNodeType.False)
|
||||
{
|
||||
}
|
||||
|
||||
public static FalseNode Create()
|
||||
{
|
||||
return FalseNode.Instance;
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class FieldNameNode : StringNodeBase
|
||||
{
|
||||
private static readonly FieldNameNode Empty = new FieldNameNode(string.Empty);
|
||||
|
||||
private FieldNameNode(ArraySegment<byte> bufferedToken)
|
||||
: base(bufferedToken, false)
|
||||
{
|
||||
}
|
||||
|
||||
private FieldNameNode(string value)
|
||||
: base(value, true)
|
||||
{
|
||||
}
|
||||
|
||||
public static FieldNameNode Create(ArraySegment<byte> bufferedToken)
|
||||
{
|
||||
if (bufferedToken.Count == 0)
|
||||
{
|
||||
return FieldNameNode.Empty;
|
||||
}
|
||||
|
||||
// In the future we can have a flyweight dictionary for system strings.
|
||||
return new FieldNameNode(bufferedToken);
|
||||
}
|
||||
}
|
||||
|
||||
private abstract class JsonTextNode : IJsonNavigatorNode
|
||||
{
|
||||
private readonly JsonNodeType jsonNodeType;
|
||||
|
||||
protected JsonTextNode(JsonNodeType jsonNodeType)
|
||||
{
|
||||
this.jsonNodeType = jsonNodeType;
|
||||
}
|
||||
|
||||
public JsonNodeType JsonNodeType
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.jsonNodeType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class NullNode : JsonTextNode
|
||||
{
|
||||
private static readonly NullNode Instance = new NullNode();
|
||||
|
||||
private NullNode()
|
||||
: base(JsonNodeType.Null)
|
||||
{
|
||||
}
|
||||
|
||||
public static NullNode Create()
|
||||
{
|
||||
return NullNode.Instance;
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class NumberNode : JsonTextNode
|
||||
{
|
||||
private static readonly NumberNode[] LiteralNumberNodes = new NumberNode[]
|
||||
{
|
||||
new NumberNode(0), new NumberNode(1), new NumberNode(2), new NumberNode(3),
|
||||
new NumberNode(4), new NumberNode(5), new NumberNode(6), new NumberNode(7),
|
||||
new NumberNode(8), new NumberNode(9), new NumberNode(10), new NumberNode(11),
|
||||
new NumberNode(12), new NumberNode(13), new NumberNode(14), new NumberNode(15),
|
||||
new NumberNode(16), new NumberNode(17), new NumberNode(18), new NumberNode(19),
|
||||
new NumberNode(20), new NumberNode(21), new NumberNode(22), new NumberNode(23),
|
||||
new NumberNode(24), new NumberNode(25), new NumberNode(26), new NumberNode(27),
|
||||
new NumberNode(28), new NumberNode(29), new NumberNode(30), new NumberNode(31),
|
||||
};
|
||||
|
||||
private readonly Lazy<double> value;
|
||||
|
||||
private NumberNode(ArraySegment<byte> bufferedToken)
|
||||
: base(JsonNodeType.Number)
|
||||
{
|
||||
this.value = new Lazy<double>(() => JsonTextUtil.GetNumberValue(bufferedToken));
|
||||
}
|
||||
|
||||
private NumberNode(double value)
|
||||
: base(JsonNodeType.Number)
|
||||
{
|
||||
this.value = new Lazy<double>(() => value);
|
||||
}
|
||||
|
||||
public double Value
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.value.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public static NumberNode Create(ArraySegment<byte> bufferedToken)
|
||||
{
|
||||
IReadOnlyList<byte> payload = bufferedToken;
|
||||
if (payload.Count == 1 && payload[0] >= '0' && payload[0] <= '9')
|
||||
{
|
||||
// Single digit number.
|
||||
return NumberNode.LiteralNumberNodes[payload[0] - '0'];
|
||||
}
|
||||
|
||||
if (payload.Count == 2 && payload[0] >= '0' && payload[0] <= '9' && payload[1] >= '0' && payload[1] <= '9')
|
||||
{
|
||||
// Two digit number.
|
||||
int index = ((payload[0] - '0') * 10) + (payload[1] - '0');
|
||||
if (index >= 0 && index < NumberNode.LiteralNumberNodes.Length)
|
||||
{
|
||||
return NumberNode.LiteralNumberNodes[index];
|
||||
}
|
||||
}
|
||||
|
||||
return new NumberNode(bufferedToken);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class ObjectNode : JsonTextNode
|
||||
{
|
||||
private static readonly ObjectNode Empty = new ObjectNode(new List<ObjectProperty>());
|
||||
private readonly List<ObjectProperty> properties;
|
||||
|
||||
private ObjectNode(List<ObjectProperty> properties)
|
||||
: base(JsonNodeType.Object)
|
||||
{
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public IReadOnlyList<ObjectProperty> Properties
|
||||
{
|
||||
get { return this.properties; }
|
||||
}
|
||||
|
||||
public static ObjectNode Create(List<ObjectProperty> properties)
|
||||
{
|
||||
if (properties.Count == 0)
|
||||
{
|
||||
return ObjectNode.Empty;
|
||||
}
|
||||
|
||||
return new ObjectNode(properties);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class StringNode : StringNodeBase
|
||||
{
|
||||
private static readonly StringNode Empty = new StringNode(string.Empty);
|
||||
|
||||
private StringNode(ArraySegment<byte> bufferedToken)
|
||||
: base(bufferedToken, true)
|
||||
{
|
||||
}
|
||||
|
||||
private StringNode(string value)
|
||||
: base(value, true)
|
||||
{
|
||||
}
|
||||
|
||||
public static StringNode Create(ArraySegment<byte> bufferedToken)
|
||||
{
|
||||
if (bufferedToken.Count == 0)
|
||||
{
|
||||
return StringNode.Empty;
|
||||
}
|
||||
|
||||
// In the future we can have a flyweight dictionary for system strings.
|
||||
return new StringNode(bufferedToken);
|
||||
}
|
||||
}
|
||||
|
||||
private abstract class StringNodeBase : JsonTextNode
|
||||
{
|
||||
private readonly Lazy<string> value;
|
||||
|
||||
protected StringNodeBase(ArraySegment<byte> bufferedToken, bool isStringNode)
|
||||
: base(isStringNode ? JsonNodeType.String : JsonNodeType.FieldName)
|
||||
{
|
||||
this.value = new Lazy<string>(() => JsonTextUtil.GetStringValue(bufferedToken));
|
||||
}
|
||||
|
||||
protected StringNodeBase(string value, bool isStringNode)
|
||||
: base(isStringNode ? JsonNodeType.String : JsonNodeType.FieldName)
|
||||
{
|
||||
this.value = new Lazy<string>(() => value);
|
||||
}
|
||||
|
||||
public string Value
|
||||
{
|
||||
get { return this.value.Value; }
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class TrueNode : JsonTextNode
|
||||
{
|
||||
private static readonly TrueNode Instance = new TrueNode();
|
||||
|
||||
private TrueNode()
|
||||
: base(JsonNodeType.True)
|
||||
{
|
||||
}
|
||||
|
||||
public static TrueNode Create()
|
||||
{
|
||||
return TrueNode.Instance;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
//-----------------------------------------------------------------------
|
||||
// <copyright file="JsonNavigator.cs" company="Microsoft Corporation">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
namespace Microsoft.Azure.Cosmos.Json
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Base abstract class for JSON navigators.
|
||||
/// The navigator defines methods that allow random access to JSON document nodes.
|
||||
/// </summary>
|
||||
internal abstract partial class JsonNavigator : IJsonNavigator
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="JsonNavigator"/> class.
|
||||
/// </summary>
|
||||
protected JsonNavigator()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="JsonSerializationFormat"/> for the IJsonNavigator.
|
||||
/// </summary>
|
||||
public abstract JsonSerializationFormat SerializationFormat { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a JsonNavigator that can navigate a supplied buffer
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer to navigate</param>
|
||||
/// <param name="skipValidation">Whether validation should be skipped.</param>
|
||||
/// <returns>A concrete JsonNavigator that can navigate the supplied buffer.</returns>
|
||||
public static IJsonNavigator Create(byte[] buffer, bool skipValidation = false)
|
||||
{
|
||||
if (buffer == null)
|
||||
{
|
||||
throw new ArgumentNullException("buffer");
|
||||
}
|
||||
|
||||
// Examine the first buffer byte to determine the serialization format
|
||||
byte firstByte = buffer[0];
|
||||
|
||||
switch ((JsonSerializationFormat)firstByte)
|
||||
{
|
||||
// Explicitly pick from the set of supported formats
|
||||
case JsonSerializationFormat.Binary:
|
||||
return new JsonBinaryNavigator(buffer, skipValidation);
|
||||
default:
|
||||
// or otherwise assume text format
|
||||
return new JsonTextNavigator(buffer, skipValidation);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets <see cref="IJsonNavigatorNode"/> of the root node.
|
||||
/// </summary>
|
||||
/// <returns><see cref="IJsonNavigatorNode"/> corresponding to the root node.</returns>
|
||||
public abstract IJsonNavigatorNode GetRootNode();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="JsonNodeType"/> type for a particular node
|
||||
/// </summary>
|
||||
/// <param name="node">The <see cref="IJsonNavigatorNode"/> of the node you want to know the type of</param>
|
||||
/// <returns><see cref="JsonNodeType"/> for the node</returns>
|
||||
public abstract JsonNodeType GetNodeType(IJsonNavigatorNode node);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the numeric value for a node
|
||||
/// </summary>
|
||||
/// <param name="numberNode">The <see cref="IJsonNavigatorNode"/> of the node you want the number value from.</param>
|
||||
/// <returns>A double that represents the number value in the node.</returns>
|
||||
public abstract double GetNumberValue(IJsonNavigatorNode numberNode);
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the buffered string value from a node.
|
||||
/// </summary>
|
||||
/// <param name="stringNode">The <see cref="IJsonNavigatorNode"/> of the node to get the buffered string from.</param>
|
||||
/// <param name="bufferedStringValue">The buffered string value if possible</param>
|
||||
/// <returns><code>true</code> if the JsonNavigator successfully got the buffered string value; <code>false</code> if the JsonNavigator failed to get the buffered string value.</returns>
|
||||
public abstract bool TryGetBufferedStringValue(IJsonNavigatorNode stringNode, out IReadOnlyList<byte> bufferedStringValue);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a string value from a node.
|
||||
/// </summary>
|
||||
/// <param name="stringNode">The <see cref="IJsonNavigatorNode"/> of the node to get the string value from.</param>
|
||||
/// <returns>The string value from the node.</returns>
|
||||
public abstract string GetStringValue(IJsonNavigatorNode stringNode);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of elements in an array node.
|
||||
/// </summary>
|
||||
/// <param name="arrayNode">The <see cref="IJsonNavigatorNode"/> of the (array) node to get the count of.</param>
|
||||
/// <returns>The number of elements in the array node.</returns>
|
||||
public abstract int GetArrayItemCount(IJsonNavigatorNode arrayNode);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the node at a particular index of an array node
|
||||
/// </summary>
|
||||
/// <param name="arrayNode">The <see cref="IJsonNavigatorNode"/> of the (array) node to index from.</param>
|
||||
/// <param name="index">The offset into the array</param>
|
||||
/// <returns>The <see cref="IJsonNavigatorNode"/> of the node at a particular index of an array node</returns>
|
||||
public abstract IJsonNavigatorNode GetArrayItemAt(IJsonNavigatorNode arrayNode, int index);
|
||||
|
||||
/// <summary>
|
||||
/// Gets an IEnumerable of <see cref="IJsonNavigatorNode"/>s for an arrayNode.
|
||||
/// </summary>
|
||||
/// <param name="arrayNode">The <see cref="IJsonNavigatorNode"/> of the array to get the items from</param>
|
||||
/// <returns>The IEnumerable of <see cref="IJsonNavigatorNode"/>s for an arrayNode.</returns>
|
||||
public abstract IEnumerable<IJsonNavigatorNode> GetArrayItems(IJsonNavigatorNode arrayNode);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of properties in an object node.
|
||||
/// </summary>
|
||||
/// <param name="objectNode">The <see cref="IJsonNavigatorNode"/> of node to get the property count from.</param>
|
||||
/// <returns>The number of properties in an object node.</returns>
|
||||
public abstract int GetObjectPropertyCount(IJsonNavigatorNode objectNode);
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get a object property from an object with a particular property name.
|
||||
/// </summary>
|
||||
/// <param name="objectNode">The <see cref="IJsonNavigatorNode"/> of object node to get a property from.</param>
|
||||
/// <param name="propertyName">The name of the property to search for.</param>
|
||||
/// <param name="objectProperty">The <see cref="ObjectProperty"/> with the specified property name if it exists.</param>
|
||||
/// <returns><code>true</code> if the JsonNavigator successfully found the <see cref="IJsonNavigatorNode"/> with the specified property name; <code>false</code> otherwise.</returns>
|
||||
public abstract bool TryGetObjectProperty(IJsonNavigatorNode objectNode, string propertyName, out ObjectProperty objectProperty);
|
||||
|
||||
/// <summary>
|
||||
/// Gets an IEnumerable of <see cref="ObjectProperty"/> properties from an object node.
|
||||
/// </summary>
|
||||
/// <param name="objectNode">The <see cref="IJsonNavigatorNode"/> of object node to get the properties from.</param>
|
||||
/// <returns>The IEnumerable of <see cref="ObjectProperty"/> properties from an object node.</returns>
|
||||
public abstract IEnumerable<ObjectProperty> GetObjectProperties(IJsonNavigatorNode objectNode);
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the buffered raw json
|
||||
/// </summary>
|
||||
/// <param name="jsonNode">The json node of interest</param>
|
||||
/// <param name="bufferedRawJson">The raw json.</param>
|
||||
/// <returns>True if bufferedRawJson was set. False otherwise.</returns>
|
||||
public abstract bool TryGetBufferedRawJson(IJsonNavigatorNode jsonNode, out IReadOnlyList<byte> bufferedRawJson);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
//-----------------------------------------------------------------------
|
||||
// <copyright file="JsonNodeType.cs" company="Microsoft Corporation">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
namespace Microsoft.Azure.Cosmos.Json
|
||||
{
|
||||
/// <summary>
|
||||
/// The enumeration of JSON node types
|
||||
/// </summary>
|
||||
internal enum JsonNodeType
|
||||
{
|
||||
/// <summary>
|
||||
/// Corresponds to the 'null' value in JSON.
|
||||
/// </summary>
|
||||
Null,
|
||||
|
||||
/// <summary>
|
||||
/// Corresponds to the 'false' value in JSON.
|
||||
/// </summary>
|
||||
False,
|
||||
|
||||
/// <summary>
|
||||
/// Corresponds to the 'true' value in JSON.
|
||||
/// </summary>
|
||||
True,
|
||||
|
||||
/// <summary>
|
||||
/// Corresponds to the number type in JSON (number = [ minus ] integer [ fraction ] [ exponent ])
|
||||
/// </summary>
|
||||
Number,
|
||||
|
||||
/// <summary>
|
||||
/// Corresponds to the string type in JSON (string = quotation-mark *char quotation-mark)
|
||||
/// </summary>
|
||||
String,
|
||||
|
||||
/// <summary>
|
||||
/// Corresponds to the array type in JSON ( begin-array [ value *( value-separator value ) ] end-array)
|
||||
/// </summary>
|
||||
Array,
|
||||
|
||||
/// <summary>
|
||||
/// Corresponds to the object type in JSON (begin-object [ member *( value-separator member ) ] end-object)
|
||||
/// </summary>
|
||||
Object,
|
||||
|
||||
/// <summary>
|
||||
/// Corresponds to the property name of a JSON object property (which is also a string).
|
||||
/// </summary>
|
||||
FieldName,
|
||||
|
||||
/// <summary>
|
||||
/// Unknown JsonNodeType.
|
||||
/// </summary>
|
||||
Unknown,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,344 @@
|
|||
//-----------------------------------------------------------------------
|
||||
// <copyright file="JsonObjectState.cs" company="Microsoft Corporation">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
namespace Microsoft.Azure.Cosmos.Json
|
||||
{
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using Microsoft.Azure.Documents;
|
||||
|
||||
/// <summary>
|
||||
/// This class maintains the current state of a JSON object/value while it is being read or written.
|
||||
/// </summary>
|
||||
internal sealed class JsonObjectState
|
||||
{
|
||||
/// <summary>
|
||||
/// This constant defines the maximum nesting depth that the parser supports.
|
||||
/// The JSON spec states that this is an implementation dependent thing, so we're just picking a value for now.
|
||||
/// FWIW .Net chose 100
|
||||
/// Note: This value needs to be a multiple of 8 and must be less than 2^15 (see asserts in the constructor)
|
||||
/// </summary>
|
||||
private const int JsonMaxNestingDepth = 128;
|
||||
|
||||
/// <summary>
|
||||
/// Flag for determining whether to throw exceptions that connote a context at the end or not started / complete.
|
||||
/// </summary>
|
||||
private readonly bool readMode;
|
||||
|
||||
/// <summary>
|
||||
/// Stores a bitmap for whether we are in an array or object context at a particular level (0 => array, 1 => object).
|
||||
/// </summary>
|
||||
private readonly byte[] nestingStackBitmap;
|
||||
|
||||
/// <summary>
|
||||
/// The current nesting stack index.
|
||||
/// </summary>
|
||||
private int nestingStackIndex;
|
||||
|
||||
/// <summary>
|
||||
/// The current JsonTokenType.
|
||||
/// </summary>
|
||||
private JsonTokenType currentTokenType;
|
||||
|
||||
/// <summary>
|
||||
/// The current JsonObjectContext.
|
||||
/// </summary>
|
||||
private JsonObjectContext currentContext;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonObjectState class.
|
||||
/// </summary>
|
||||
/// <param name="readMode">Flag for determining whether to throw exceptions that correspond to a JsonReader or JsonWriter.</param>
|
||||
public JsonObjectState(bool readMode)
|
||||
{
|
||||
Debug.Assert(JsonMaxNestingDepth % 8 == 0, "JsonMaxNestingDepth must be multiple of 8");
|
||||
Debug.Assert(JsonMaxNestingDepth < (1 << 15), "JsonMaxNestingDepth must be less than 2^15");
|
||||
|
||||
this.readMode = readMode;
|
||||
this.nestingStackBitmap = new byte[JsonMaxNestingDepth / 8];
|
||||
this.nestingStackIndex = -1;
|
||||
this.currentTokenType = JsonTokenType.NotStarted;
|
||||
this.currentContext = JsonObjectContext.None;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JsonObjectContext enum
|
||||
/// </summary>
|
||||
private enum JsonObjectContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Context at the start of the object state.
|
||||
/// </summary>
|
||||
None,
|
||||
|
||||
/// <summary>
|
||||
/// Context when state is in an array.
|
||||
/// </summary>
|
||||
Array,
|
||||
|
||||
/// <summary>
|
||||
/// Context when state is in an object.
|
||||
/// </summary>
|
||||
Object,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current depth (level of nesting).
|
||||
/// </summary>
|
||||
public int CurrentDepth
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.nestingStackIndex + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current JsonTokenType.
|
||||
/// </summary>
|
||||
public JsonTokenType CurrentTokenType
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.currentTokenType;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether a property is expected.
|
||||
/// </summary>
|
||||
public bool IsPropertyExpected
|
||||
{
|
||||
get
|
||||
{
|
||||
return (this.currentTokenType != JsonTokenType.FieldName) && (this.currentContext == JsonObjectContext.Object);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the current context is an array.
|
||||
/// </summary>
|
||||
public bool InArrayContext
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.currentContext == JsonObjectContext.Array;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the current context in an object.
|
||||
/// </summary>
|
||||
public bool InObjectContext
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.currentContext == JsonObjectContext.Object;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current JsonObjectContext
|
||||
/// </summary>
|
||||
private JsonObjectContext RetrieveCurrentContext
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.nestingStackIndex < 0)
|
||||
{
|
||||
return JsonObjectContext.None;
|
||||
}
|
||||
|
||||
return (this.nestingStackBitmap[this.nestingStackIndex / 8] & this.Mask) == 0 ? JsonObjectContext.Array : JsonObjectContext.Object;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a mask to use to get the current context from the nesting stack
|
||||
/// </summary>
|
||||
private byte Mask
|
||||
{
|
||||
get
|
||||
{
|
||||
return (byte)(1 << (this.nestingStackIndex % 8));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a JsonTokenType.
|
||||
/// </summary>
|
||||
/// <param name="jsonTokenType">The JsonTokenType to register.</param>
|
||||
public void RegisterToken(JsonTokenType jsonTokenType)
|
||||
{
|
||||
switch (jsonTokenType)
|
||||
{
|
||||
case JsonTokenType.String:
|
||||
case JsonTokenType.Number:
|
||||
case JsonTokenType.True:
|
||||
case JsonTokenType.False:
|
||||
case JsonTokenType.Null:
|
||||
this.RegisterValue(jsonTokenType);
|
||||
break;
|
||||
case JsonTokenType.BeginArray:
|
||||
this.RegisterBeginArray();
|
||||
break;
|
||||
case JsonTokenType.EndArray:
|
||||
this.RegisterEndArray();
|
||||
break;
|
||||
case JsonTokenType.BeginObject:
|
||||
this.RegisterBeginObject();
|
||||
break;
|
||||
case JsonTokenType.EndObject:
|
||||
this.RegisterEndObject();
|
||||
break;
|
||||
case JsonTokenType.FieldName:
|
||||
this.RegisterFieldName();
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, RMResources.UnexpectedJsonTokenType, jsonTokenType));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pushes a JsonObjectContext onto the nesting stack.
|
||||
/// </summary>
|
||||
/// <param name="isArray">Whether the JsonObjectContext is an array.</param>
|
||||
private void Push(bool isArray)
|
||||
{
|
||||
if (this.nestingStackIndex + 1 >= JsonMaxNestingDepth)
|
||||
{
|
||||
throw new InvalidOperationException(RMResources.JsonMaxNestingExceeded);
|
||||
}
|
||||
|
||||
this.nestingStackIndex++;
|
||||
|
||||
if (isArray)
|
||||
{
|
||||
this.nestingStackBitmap[this.nestingStackIndex / 8] &= (byte)~this.Mask;
|
||||
this.currentContext = JsonObjectContext.Array;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.nestingStackBitmap[this.nestingStackIndex / 8] |= this.Mask;
|
||||
this.currentContext = JsonObjectContext.Object;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers any json token type.
|
||||
/// </summary>
|
||||
/// <param name="jsonTokenType">The jsonTokenType to register</param>
|
||||
private void RegisterValue(JsonTokenType jsonTokenType)
|
||||
{
|
||||
if ((this.currentContext == JsonObjectContext.Object) && (this.currentTokenType != JsonTokenType.FieldName))
|
||||
{
|
||||
throw new JsonMissingPropertyException();
|
||||
}
|
||||
|
||||
if ((this.currentContext == JsonObjectContext.None) && (this.currentTokenType != JsonTokenType.NotStarted))
|
||||
{
|
||||
throw new JsonPropertyArrayOrObjectNotStartedException();
|
||||
}
|
||||
|
||||
this.currentTokenType = jsonTokenType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a beginning of a json array ('[')
|
||||
/// </summary>
|
||||
private void RegisterBeginArray()
|
||||
{
|
||||
// An array start is also a value
|
||||
this.RegisterValue(JsonTokenType.BeginArray);
|
||||
this.Push(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers the end of a json array (']')
|
||||
/// </summary>
|
||||
private void RegisterEndArray()
|
||||
{
|
||||
if (this.currentContext != JsonObjectContext.Array)
|
||||
{
|
||||
if (this.readMode)
|
||||
{
|
||||
throw new JsonUnexpectedEndArrayException();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new JsonArrayNotStartedException();
|
||||
}
|
||||
}
|
||||
|
||||
this.nestingStackIndex--;
|
||||
this.currentTokenType = JsonTokenType.EndArray;
|
||||
this.currentContext = this.RetrieveCurrentContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a beginning of a json object ('{')
|
||||
/// </summary>
|
||||
private void RegisterBeginObject()
|
||||
{
|
||||
// An object start is also a value
|
||||
this.RegisterValue(JsonTokenType.BeginObject);
|
||||
this.Push(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a end of a json object ('}')
|
||||
/// </summary>
|
||||
private void RegisterEndObject()
|
||||
{
|
||||
if (this.currentContext != JsonObjectContext.Object)
|
||||
{
|
||||
if (this.readMode)
|
||||
{
|
||||
throw new JsonUnexpectedEndObjectException();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new JsonObjectNotStartedException();
|
||||
}
|
||||
}
|
||||
|
||||
// check if we have a property name but not a value
|
||||
if (this.currentTokenType == JsonTokenType.FieldName)
|
||||
{
|
||||
if (this.readMode)
|
||||
{
|
||||
throw new JsonUnexpectedEndObjectException();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new JsonNotCompleteException();
|
||||
}
|
||||
}
|
||||
|
||||
this.nestingStackIndex--;
|
||||
this.currentTokenType = JsonTokenType.EndObject;
|
||||
this.currentContext = this.RetrieveCurrentContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register a Json FieldName
|
||||
/// </summary>
|
||||
private void RegisterFieldName()
|
||||
{
|
||||
if (this.currentContext != JsonObjectContext.Object)
|
||||
{
|
||||
throw new JsonObjectNotStartedException();
|
||||
}
|
||||
|
||||
if (this.currentTokenType == JsonTokenType.FieldName)
|
||||
{
|
||||
throw new JsonPropertyAlreadyAddedException();
|
||||
}
|
||||
|
||||
this.currentTokenType = JsonTokenType.FieldName;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,403 @@
|
|||
//-----------------------------------------------------------------------
|
||||
// <copyright file="JsonParseException.cs" company="Microsoft Corporation">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
namespace Microsoft.Azure.Cosmos.Json
|
||||
{
|
||||
using System.Net;
|
||||
using Microsoft.Azure.Documents;
|
||||
|
||||
/// <summary>
|
||||
/// Abstract class that all JsonParseExceptions will derive from.
|
||||
/// </summary>
|
||||
internal abstract class JsonParseException : DocumentClientException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonParseException class.
|
||||
/// </summary>
|
||||
/// <param name="message">The exception message for the JsonParseException</param>
|
||||
protected JsonParseException(string message)
|
||||
: base(message, null, HttpStatusCode.BadRequest)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JsonParseException for MissingClosingQuote
|
||||
/// </summary>
|
||||
internal sealed class JsonMissingClosingQuoteException : JsonParseException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonMissingClosingQuoteException class.
|
||||
/// </summary>
|
||||
public JsonMissingClosingQuoteException()
|
||||
: base(RMResources.JsonMissingClosingQuote)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JsonParseException for NotFieldnameToken
|
||||
/// </summary>
|
||||
internal sealed class JsonNotFieldnameTokenException : JsonParseException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonNotFieldnameTokenException class.
|
||||
/// </summary>
|
||||
public JsonNotFieldnameTokenException()
|
||||
: base(RMResources.JsonNotFieldnameToken)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JsonParseException for InvalidParameter
|
||||
/// </summary>
|
||||
internal sealed class JsonInvalidParameterException : JsonParseException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonInvalidParameterException class.
|
||||
/// </summary>
|
||||
public JsonInvalidParameterException()
|
||||
: base(RMResources.JsonInvalidParameter)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JsonParseException for NumberTooLong
|
||||
/// </summary>
|
||||
internal sealed class JsonNumberTooLongException : JsonParseException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonNumberTooLongException class.
|
||||
/// </summary>
|
||||
public JsonNumberTooLongException()
|
||||
: base(RMResources.JsonNumberTooLong)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JsonParseException for MissingNameSeparator
|
||||
/// </summary>
|
||||
internal sealed class JsonMissingNameSeparatorException : JsonParseException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonMissingNameSeparatorException class.
|
||||
/// </summary>
|
||||
public JsonMissingNameSeparatorException()
|
||||
: base(RMResources.JsonMissingNameSeparator)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JsonParseException for UnexpectedToken
|
||||
/// </summary>
|
||||
internal sealed class JsonUnexpectedTokenException : JsonParseException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonUnexpectedTokenException class.
|
||||
/// </summary>
|
||||
public JsonUnexpectedTokenException()
|
||||
: base(RMResources.JsonUnexpectedToken)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JsonParseException for UnexpectedEndArray
|
||||
/// </summary>
|
||||
internal sealed class JsonUnexpectedEndArrayException : JsonParseException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonUnexpectedEndArrayException class.
|
||||
/// </summary>
|
||||
public JsonUnexpectedEndArrayException()
|
||||
: base(RMResources.JsonUnexpectedEndArray)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JsonParseException for UnexpectedEndObject
|
||||
/// </summary>
|
||||
internal sealed class JsonUnexpectedEndObjectException : JsonParseException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonUnexpectedEndObjectException class.
|
||||
/// </summary>
|
||||
public JsonUnexpectedEndObjectException()
|
||||
: base(RMResources.JsonUnexpectedEndObject)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JsonParseException for InvalidToken
|
||||
/// </summary>
|
||||
internal sealed class JsonInvalidTokenException : JsonParseException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonInvalidTokenException class.
|
||||
/// </summary>
|
||||
public JsonInvalidTokenException()
|
||||
: base(RMResources.JsonInvalidToken)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JsonParseException for UnexpectedNameSeparator
|
||||
/// </summary>
|
||||
internal sealed class JsonUnexpectedNameSeparatorException : JsonParseException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonUnexpectedNameSeparatorException class.
|
||||
/// </summary>
|
||||
public JsonUnexpectedNameSeparatorException()
|
||||
: base(RMResources.JsonUnexpectedNameSeparator)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JsonParseException for UnexpectedValueSeparator
|
||||
/// </summary>
|
||||
internal sealed class JsonUnexpectedValueSeparatorException : JsonParseException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonUnexpectedValueSeparatorException class.
|
||||
/// </summary>
|
||||
public JsonUnexpectedValueSeparatorException()
|
||||
: base(RMResources.JsonUnexpectedValueSeparator)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JsonParseException for MissingEndObject
|
||||
/// </summary>
|
||||
internal sealed class JsonMissingEndObjectException : JsonParseException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonMissingEndObjectException class.
|
||||
/// </summary>
|
||||
public JsonMissingEndObjectException()
|
||||
: base(RMResources.JsonMissingEndObject)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JsonParseException for MissingEndArray
|
||||
/// </summary>
|
||||
internal sealed class JsonMissingEndArrayException : JsonParseException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonMissingEndArrayException class.
|
||||
/// </summary>
|
||||
public JsonMissingEndArrayException()
|
||||
: base(RMResources.JsonMissingEndArray)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JsonParseException for NotStringToken
|
||||
/// </summary>
|
||||
internal sealed class JsonNotStringTokenException : JsonParseException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonNotStringTokenException class.
|
||||
/// </summary>
|
||||
public JsonNotStringTokenException()
|
||||
: base(RMResources.JsonNotStringToken)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JsonParseException for MaxNestingExceeded
|
||||
/// </summary>
|
||||
internal sealed class JsonMaxNestingExceededException : JsonParseException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonMaxNestingExceededException class.
|
||||
/// </summary>
|
||||
public JsonMaxNestingExceededException()
|
||||
: base(RMResources.JsonMaxNestingExceeded)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JsonParseException for InvalidEscapedCharacter
|
||||
/// </summary>
|
||||
internal sealed class JsonInvalidEscapedCharacterException : JsonParseException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonInvalidEscapedCharacterException class.
|
||||
/// </summary>
|
||||
public JsonInvalidEscapedCharacterException()
|
||||
: base(RMResources.JsonInvalidEscapedCharacter)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JsonParseException for InvalidUnicodeEscape
|
||||
/// </summary>
|
||||
internal sealed class JsonInvalidUnicodeEscapeException : JsonParseException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonInvalidUnicodeEscapeException class.
|
||||
/// </summary>
|
||||
public JsonInvalidUnicodeEscapeException()
|
||||
: base(RMResources.JsonInvalidUnicodeEscape)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JsonParseException for InvalidStringCharacter
|
||||
/// </summary>
|
||||
internal sealed class JsonInvalidStringCharacterException : JsonParseException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonInvalidStringCharacterException class.
|
||||
/// </summary>
|
||||
public JsonInvalidStringCharacterException()
|
||||
: base(RMResources.JsonInvalidStringCharacter)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JsonParseException for InvalidNumber
|
||||
/// </summary>
|
||||
internal sealed class JsonInvalidNumberException : JsonParseException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonInvalidNumberException class.
|
||||
/// </summary>
|
||||
public JsonInvalidNumberException()
|
||||
: base(RMResources.JsonInvalidNumber)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JsonParseException for NotNumberToken
|
||||
/// </summary>
|
||||
internal sealed class JsonNotNumberTokenException : JsonParseException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonNotNumberTokenException class.
|
||||
/// </summary>
|
||||
public JsonNotNumberTokenException()
|
||||
: base(RMResources.JsonNotNumberToken)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JsonParseException for NumberOutOfRange
|
||||
/// </summary>
|
||||
internal sealed class JsonNumberOutOfRangeException : JsonParseException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonNumberOutOfRangeException class.
|
||||
/// </summary>
|
||||
public JsonNumberOutOfRangeException()
|
||||
: base(RMResources.JsonNumberOutOfRange)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JsonParseException for MissingProperty
|
||||
/// </summary>
|
||||
internal sealed class JsonMissingPropertyException : JsonParseException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonMissingPropertyException class.
|
||||
/// </summary>
|
||||
public JsonMissingPropertyException()
|
||||
: base(RMResources.JsonMissingProperty)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JsonParseException for PropertyAlreadyAdded
|
||||
/// </summary>
|
||||
internal sealed class JsonPropertyAlreadyAddedException : JsonParseException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonPropertyAlreadyAddedException class.
|
||||
/// </summary>
|
||||
public JsonPropertyAlreadyAddedException()
|
||||
: base(RMResources.JsonPropertyAlreadyAdded)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JsonParseException for ObjectNotStarted
|
||||
/// </summary>
|
||||
internal sealed class JsonObjectNotStartedException : JsonParseException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonObjectNotStartedException class.
|
||||
/// </summary>
|
||||
public JsonObjectNotStartedException()
|
||||
: base(RMResources.JsonObjectNotStarted)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JsonParseException for ArrayNotStarted
|
||||
/// </summary>
|
||||
internal sealed class JsonArrayNotStartedException : JsonParseException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonArrayNotStartedException class.
|
||||
/// </summary>
|
||||
public JsonArrayNotStartedException()
|
||||
: base(RMResources.JsonArrayNotStarted)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JsonParseException for PropertyArrayOrObjectNotStarted
|
||||
/// </summary>
|
||||
internal sealed class JsonPropertyArrayOrObjectNotStartedException : JsonParseException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonPropertyArrayOrObjectNotStartedException class.
|
||||
/// </summary>
|
||||
public JsonPropertyArrayOrObjectNotStartedException()
|
||||
: base(RMResources.JsonPropertyArrayOrObjectNotStarted)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JsonParseException for NotComplete
|
||||
/// </summary>
|
||||
internal sealed class JsonNotCompleteException : JsonParseException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonNotCompleteException class.
|
||||
/// </summary>
|
||||
public JsonNotCompleteException()
|
||||
: base(RMResources.JsonNotComplete)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,169 @@
|
|||
//-----------------------------------------------------------------------
|
||||
// <copyright file="JsonReader.cs" company="Microsoft Corporation">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
namespace Microsoft.Azure.Cosmos.Json
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
/// <summary>
|
||||
/// Base abstract class for JSON readers.
|
||||
/// The reader defines methods that allow for reading a JSON encoded value as a stream of tokens.
|
||||
/// The tokens are traversed in the same order as they appear in the JSON document.
|
||||
/// </summary>
|
||||
internal abstract partial class JsonReader : IJsonReader
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="JsonObjectState"/>
|
||||
/// </summary>
|
||||
protected readonly JsonObjectState JsonObjectState;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to skip validation.
|
||||
/// </summary>
|
||||
protected readonly bool SkipValidation;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonReader class.
|
||||
/// </summary>
|
||||
/// <param name="skipValidation">Whether or not to skip validation.</param>
|
||||
protected JsonReader(bool skipValidation)
|
||||
{
|
||||
this.JsonObjectState = new JsonObjectState(true);
|
||||
this.SkipValidation = skipValidation;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="JsonSerializationFormat"/> for the JsonReader
|
||||
/// </summary>
|
||||
public abstract JsonSerializationFormat SerializationFormat { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current level of nesting of the JSON that the JsonReader is reading.
|
||||
/// </summary>
|
||||
public int CurrentDepth
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.JsonObjectState.CurrentDepth;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="JsonTokenType"/> of the current token that the JsonReader is about to read.
|
||||
/// </summary>
|
||||
public JsonTokenType CurrentTokenType
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.JsonObjectState.CurrentTokenType;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a JsonReader that can read a supplied stream (assumes UTF-8 encoding).
|
||||
/// </summary>
|
||||
/// <param name="stream">the stream to read.</param>
|
||||
/// <param name="skipvalidation">whether or not to skip validation.</param>
|
||||
/// <returns>a concrete JsonReader that can read the supplied stream.</returns>
|
||||
public static IJsonReader Create(Stream stream, bool skipvalidation = false)
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
throw new ArgumentNullException("stream");
|
||||
}
|
||||
|
||||
BinaryReader tempBinaryReader = new BinaryReader(stream, Encoding.UTF8);
|
||||
|
||||
// examine the first buffer byte to determine the serialization format
|
||||
byte firstbyte = tempBinaryReader.ReadByte();
|
||||
|
||||
// you have to rewind the stream since even "peeking" still reads it into the bufferedstream
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
// explicitly pick from the set of supported formats, or otherwise assume text format
|
||||
switch ((JsonSerializationFormat)firstbyte)
|
||||
{
|
||||
case JsonSerializationFormat.Binary:
|
||||
return new JsonBinaryReader(stream, skipvalidation);
|
||||
default:
|
||||
return new JsonTextReader(stream, Encoding.UTF8, skipvalidation);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a JsonTextReader that can read a supplied stream with the specified encoding.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to read.</param>
|
||||
/// <param name="encoding">The encoding of the text (UTF-8, UTF-16 / Unicode, or UTF-32).</param>
|
||||
/// <param name="skipValidation">Whether or not to skip validation.</param>
|
||||
/// <returns>A concrete JsonReader that can read the supplied stream.</returns>
|
||||
public static IJsonReader CreateTextReaderWithEncoding(Stream stream, Encoding encoding, bool skipValidation = false)
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
throw new ArgumentNullException("stream");
|
||||
}
|
||||
|
||||
if (encoding != Encoding.UTF8 && encoding != Encoding.Unicode && encoding != Encoding.UTF32)
|
||||
{
|
||||
throw new ArgumentException("Json Text only supports UTF8, UTF16/Unicode, or UTF32");
|
||||
}
|
||||
|
||||
return new JsonTextReader(stream, encoding, skipValidation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a JsonReader that can read from the supplied byte array (assumes utf-8 encoding).
|
||||
/// </summary>
|
||||
/// <param name="buffer">The byte array to read from.</param>
|
||||
/// <param name="skipValidation">Whether or not to skip validation.</param>
|
||||
/// <returns>A concrete JsonReader that can read the supplied byte array.</returns>
|
||||
public static IJsonReader Create(byte[] buffer, bool skipValidation = false)
|
||||
{
|
||||
if (buffer == null)
|
||||
{
|
||||
throw new ArgumentNullException("buffer");
|
||||
}
|
||||
|
||||
byte firstByte = buffer[0];
|
||||
|
||||
// Explicitly pick from the set of supported formats, or otherwise assume text format
|
||||
switch ((JsonSerializationFormat)firstByte)
|
||||
{
|
||||
case JsonSerializationFormat.Binary:
|
||||
return new JsonBinaryReader(buffer, skipValidation);
|
||||
default:
|
||||
return new JsonTextReader(buffer, skipValidation);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Advances the JsonReader by one token.
|
||||
/// </summary>
|
||||
/// <returns><code>true</code> if the JsonReader successfully advanced to the next token; <code>false</code> if the JsonReader has passed the end of the JSON.</returns>
|
||||
public abstract bool Read();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the next JSON token from the JsonReader as a double.
|
||||
/// </summary>
|
||||
/// <returns>The next JSON token from the JsonReader as a double.</returns>
|
||||
public abstract double GetNumberValue();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the next JSON token from the JsonReader as a string.
|
||||
/// </summary>
|
||||
/// <returns>The next JSON token from the JsonReader as a string.</returns>
|
||||
public abstract string GetStringValue();
|
||||
|
||||
/// <summary>
|
||||
/// Gets next JSON token from the JsonReader as a raw series of bytes that is buffered.
|
||||
/// </summary>
|
||||
/// <returns>The next JSON token from the JsonReader as a raw series of bytes that is buffered.</returns>
|
||||
public abstract IReadOnlyList<byte> GetBufferedRawJsonToken();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
//-----------------------------------------------------------------------
|
||||
// <copyright file="JsonSerializationFormat.cs" company="Microsoft Corporation">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
namespace Microsoft.Azure.Cosmos.Json
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines JSON different serialization Formats
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Every enumeration type has an underlying type, which can be any integral type except char.
|
||||
/// The default underlying type of enumeration elements is integer.
|
||||
/// To declare an enum of another integral type, such as byte, use a colon after the identifier followed by the type, as shown in the following example.
|
||||
/// </remarks>
|
||||
internal enum JsonSerializationFormat : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Plain text
|
||||
/// </summary>
|
||||
Text = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Binary Encoding
|
||||
/// </summary>
|
||||
Binary = 128,
|
||||
|
||||
/// <summary>
|
||||
/// HybridRow Binary Encoding
|
||||
/// </summary>
|
||||
HybridRow = 129,
|
||||
|
||||
// All other format values need to be > 127,
|
||||
// otherwise a valid JSON starting character (0-9, f[alse], t[rue], n[ull],{,[,") might be interpreted as a serialization format.
|
||||
}
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
//-----------------------------------------------------------------------
|
||||
// <copyright file="JsonTextUtil.cs" company="Microsoft Corporation">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
namespace Microsoft.Azure.Cosmos.Json
|
||||
{
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
/// <summary>
|
||||
/// Common utility class for JsonTextReader and JsonTextNavigator.
|
||||
/// Please treat this class as private.
|
||||
/// </summary>
|
||||
internal static class JsonTextUtil
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the number value from the specified token.
|
||||
/// </summary>
|
||||
/// <param name="bufferedToken">The jsonToken returned from that holds the raw number that you want the value of.</param>
|
||||
/// <returns>The number value from the specified token.</returns>
|
||||
public static double GetNumberValue(ArraySegment<byte> bufferedToken)
|
||||
{
|
||||
byte[] rawBufferedTokenArray = bufferedToken.Array;
|
||||
int offset = bufferedToken.Offset;
|
||||
int count = bufferedToken.Count;
|
||||
string stringDouble = Encoding.UTF8.GetString(rawBufferedTokenArray, offset, count);
|
||||
return double.Parse(stringDouble);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the string value from the specified token.
|
||||
/// </summary>
|
||||
/// <param name="bufferedToken">The buffered token.</param>
|
||||
/// <returns>The string value from the specified token.</returns>
|
||||
public static string GetStringValue(ArraySegment<byte> bufferedToken)
|
||||
{
|
||||
// Offsetting by an additional character and removing 2 from the length since I want to skip the quotes.
|
||||
ArraySegment<byte> stringToken = new ArraySegment<byte>(bufferedToken.Array, bufferedToken.Offset + 1, bufferedToken.Count - 2);
|
||||
|
||||
return JsonTextUtil.UnescapeJson(Encoding.UTF8.GetChars(stringToken.Array, stringToken.Offset, stringToken.Count));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unescapes a json.
|
||||
/// </summary>
|
||||
/// <param name="escapedString">The escaped json.</param>
|
||||
/// <returns>The unescaped json.</returns>
|
||||
public static string UnescapeJson(char[] escapedString)
|
||||
{
|
||||
int readOffset = 0;
|
||||
int writeOffset = 0;
|
||||
|
||||
while (readOffset != escapedString.Length)
|
||||
{
|
||||
if (escapedString[readOffset] == '\\')
|
||||
{
|
||||
// Consume the '\' character
|
||||
readOffset++;
|
||||
|
||||
// Figure out how to escape.
|
||||
switch (escapedString[readOffset++])
|
||||
{
|
||||
case 'b':
|
||||
escapedString[writeOffset++] = '\b';
|
||||
break;
|
||||
case 'f':
|
||||
escapedString[writeOffset++] = '\f';
|
||||
break;
|
||||
case 'n':
|
||||
escapedString[writeOffset++] = '\n';
|
||||
break;
|
||||
case 'r':
|
||||
escapedString[writeOffset++] = '\r';
|
||||
break;
|
||||
case 't':
|
||||
escapedString[writeOffset++] = '\t';
|
||||
break;
|
||||
case '\\':
|
||||
escapedString[writeOffset++] = '\\';
|
||||
break;
|
||||
case '"':
|
||||
escapedString[writeOffset++] = '"';
|
||||
break;
|
||||
case '/':
|
||||
escapedString[writeOffset++] = '/';
|
||||
break;
|
||||
case 'u':
|
||||
// parse Json unicode sequence: \uXXXX(\uXXXX)
|
||||
// Start by reading XXXX. \u is already read.
|
||||
char unescpaedUnicodeCharacter = (char)0;
|
||||
for (int sequenceIndex = 0; sequenceIndex < 4; sequenceIndex++)
|
||||
{
|
||||
unescpaedUnicodeCharacter <<= 4;
|
||||
|
||||
char currentCharacter = escapedString[readOffset++];
|
||||
if (currentCharacter >= '0' && currentCharacter <= '9')
|
||||
{
|
||||
unescpaedUnicodeCharacter += (char)(currentCharacter - '0');
|
||||
}
|
||||
else if (currentCharacter >= 'A' && currentCharacter <= 'F')
|
||||
{
|
||||
unescpaedUnicodeCharacter += (char)(10 + currentCharacter - 'A');
|
||||
}
|
||||
else if (currentCharacter >= 'a' && currentCharacter <= 'f')
|
||||
{
|
||||
unescpaedUnicodeCharacter += (char)(10 + currentCharacter - 'a');
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new JsonInvalidEscapedCharacterException();
|
||||
}
|
||||
}
|
||||
|
||||
escapedString[writeOffset++] = unescpaedUnicodeCharacter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
escapedString[writeOffset++] = escapedString[readOffset++];
|
||||
}
|
||||
}
|
||||
|
||||
return new string(escapedString, 0, writeOffset);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
//-----------------------------------------------------------------------
|
||||
// <copyright file="JsonTokenType.cs" company="Microsoft Corporation">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
namespace Microsoft.Azure.Cosmos.Json
|
||||
{
|
||||
/// <summary>
|
||||
/// Enum of JsonTokenType
|
||||
/// </summary>
|
||||
internal enum JsonTokenType
|
||||
{
|
||||
/// <summary>
|
||||
/// Reserved for no other value
|
||||
/// </summary>
|
||||
NotStarted,
|
||||
|
||||
/// <summary>
|
||||
/// Corresponds to the beginning of a JSON array ('[')
|
||||
/// </summary>
|
||||
BeginArray,
|
||||
|
||||
/// <summary>
|
||||
/// Corresponds to the end of a JSON array (']')
|
||||
/// </summary>
|
||||
EndArray,
|
||||
|
||||
/// <summary>
|
||||
/// Corresponds to the beginning of a JSON object ('{')
|
||||
/// </summary>
|
||||
BeginObject,
|
||||
|
||||
/// <summary>
|
||||
/// Corresponds to the end of a JSON object ('}')
|
||||
/// </summary>
|
||||
EndObject,
|
||||
|
||||
/// <summary>
|
||||
/// Corresponds to a JSON string.
|
||||
/// </summary>
|
||||
String,
|
||||
|
||||
/// <summary>
|
||||
/// Corresponds to a JSON number.
|
||||
/// </summary>
|
||||
Number,
|
||||
|
||||
/// <summary>
|
||||
/// Corresponds to the JSON 'true' value.
|
||||
/// </summary>
|
||||
True,
|
||||
|
||||
/// <summary>
|
||||
/// Corresponds to the JSON 'false' value.
|
||||
/// </summary>
|
||||
False,
|
||||
|
||||
/// <summary>
|
||||
/// Corresponds to the JSON 'null' value.
|
||||
/// </summary>
|
||||
Null,
|
||||
|
||||
/// <summary>
|
||||
/// Corresponds to the JSON fieldname in a JSON object.
|
||||
/// </summary>
|
||||
FieldName,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,578 @@
|
|||
//-----------------------------------------------------------------------
|
||||
// <copyright file="JsonWriter.JsonBinaryWriter.cs" company="Microsoft Corporation">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
namespace Microsoft.Azure.Cosmos.Json
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
/// <summary>
|
||||
/// Partial class for the JsonWriter that has a private JsonTextWriter below.
|
||||
/// </summary>
|
||||
internal abstract partial class JsonWriter : IJsonWriter
|
||||
{
|
||||
/// <summary>
|
||||
/// Concrete implementation of <see cref="JsonWriter"/> that knows how to serialize to binary encoding.
|
||||
/// </summary>
|
||||
private sealed class JsonBinaryWriter : JsonWriter
|
||||
{
|
||||
private const int TypeMarker = 1;
|
||||
private const int OneByteLength = 1;
|
||||
private const int OneByteCount = 1;
|
||||
private const int TwoByteLength = 2;
|
||||
private const int TwoByteCount = 2;
|
||||
private const int FourByteLength = 4;
|
||||
private const int FourByteCount = 4;
|
||||
|
||||
/// <summary>
|
||||
/// Writer used to write fully materialized context to the internal stream.
|
||||
/// </summary>
|
||||
private readonly BinaryWriter binaryWriter;
|
||||
|
||||
/// <summary>
|
||||
/// With binary encoding all the json elements are length prefixed,
|
||||
/// unfortunately the caller of this class only provides what tokens to write.
|
||||
/// This means that whenever a user call WriteObject/ArrayStart we don't know the length of said object or array
|
||||
/// until WriteObject/ArrayEnd is invoked.
|
||||
/// To get around this we reserve some space for the length and write to it when the user supplies the end token.
|
||||
/// This stack remembers for each nesting level where it begins and how many items it has.
|
||||
/// </summary>
|
||||
private readonly Stack<BeginOffsetAndCount> bufferedContexts;
|
||||
|
||||
/// <summary>
|
||||
/// With binary encoding json elements like arrays and object are prefixed with a length in bytes and optionally a count.
|
||||
/// This flag just determines whether you want to serialize the count, since it's optional and up to the user to make the
|
||||
/// tradeoff between O(1) .Count() operation as the cost of additional storage.
|
||||
/// </summary>
|
||||
private readonly bool serializeCount;
|
||||
|
||||
/// <summary>
|
||||
/// When a user writes an open array or object we reserve this much space for the type marker + length + count
|
||||
/// And correct it later when they write a close array or object.
|
||||
/// </summary>
|
||||
private readonly int reservationSize;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonBinaryWriter class.
|
||||
/// </summary>
|
||||
/// <param name="skipValidation">Whether to skip validation on the JsonObjectState.</param>
|
||||
/// <param name="serializeCount">Whether to serialize the count for object and array typemarkers.</param>
|
||||
public JsonBinaryWriter(bool skipValidation, bool serializeCount = false)
|
||||
: base(skipValidation)
|
||||
{
|
||||
this.binaryWriter = new BinaryWriter(new MemoryStream());
|
||||
this.bufferedContexts = new Stack<BeginOffsetAndCount>();
|
||||
this.serializeCount = serializeCount;
|
||||
this.reservationSize = TypeMarker + TwoByteLength + (this.serializeCount ? TwoByteCount : 0);
|
||||
|
||||
// Write the serialization format as the very first byte
|
||||
this.binaryWriter.Write((byte)JsonSerializationFormat.Binary);
|
||||
|
||||
// Push on the outermost context
|
||||
this.bufferedContexts.Push(new BeginOffsetAndCount(this.CurrentLength));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the SerializationFormat of the JsonWriter.
|
||||
/// </summary>
|
||||
public override JsonSerializationFormat SerializationFormat
|
||||
{
|
||||
get
|
||||
{
|
||||
return JsonSerializationFormat.Binary;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current length of the internal buffer.
|
||||
/// </summary>
|
||||
public override long CurrentLength
|
||||
{
|
||||
get
|
||||
{
|
||||
this.binaryWriter.Flush();
|
||||
return this.binaryWriter.BaseStream.Position;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the object start symbol to internal buffer.
|
||||
/// </summary>
|
||||
public override void WriteObjectStart()
|
||||
{
|
||||
this.WriterArrayOrObjectStart(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the object end symbol to the internal buffer.
|
||||
/// </summary>
|
||||
public override void WriteObjectEnd()
|
||||
{
|
||||
this.WriteArrayOrObjectEnd(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the array start symbol to the internal buffer.
|
||||
/// </summary>
|
||||
public override void WriteArrayStart()
|
||||
{
|
||||
this.WriterArrayOrObjectStart(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the array end token to the internal buffer.
|
||||
/// </summary>
|
||||
public override void WriteArrayEnd()
|
||||
{
|
||||
this.WriteArrayOrObjectEnd(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a field name to the the internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="fieldName">The name of the field to write.</param>
|
||||
public override void WriteFieldName(string fieldName)
|
||||
{
|
||||
this.WriteFieldNameOrString(true, fieldName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a string to the internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="value">The value of the string to write.</param>
|
||||
public override void WriteStringValue(string value)
|
||||
{
|
||||
this.WriteFieldNameOrString(false, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes an integer to the internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="value">The value of the integer to write.</param>
|
||||
public override void WriteIntValue(long value)
|
||||
{
|
||||
this.JsonObjectState.RegisterToken(JsonTokenType.Number);
|
||||
|
||||
this.WriteIntegerInternal(value);
|
||||
this.bufferedContexts.Peek().Count++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a number to the internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="value">The value of the number to write.</param>
|
||||
public override void WriteNumberValue(double value)
|
||||
{
|
||||
this.JsonObjectState.RegisterToken(JsonTokenType.Number);
|
||||
|
||||
// The maximum integer value that can be stored in an IEEE 754 double type w/o losing precision
|
||||
const double MaxFullPrecisionValue = ((long)1) << 53;
|
||||
|
||||
// Check if the number is an integer
|
||||
double truncatedValue = Math.Floor(value);
|
||||
if ((truncatedValue == value) && (value >= -MaxFullPrecisionValue) && (value <= MaxFullPrecisionValue))
|
||||
{
|
||||
// The number does not have any decimals and fits in a 64-bit value
|
||||
this.WriteIntegerInternal((long)value);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.binaryWriter.Write(JsonBinaryEncoding.TypeMarker.Double);
|
||||
this.binaryWriter.Write(value);
|
||||
}
|
||||
|
||||
this.bufferedContexts.Peek().Count++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a boolean to the internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="value">The value of the boolean to write.</param>
|
||||
public override void WriteBoolValue(bool value)
|
||||
{
|
||||
this.JsonObjectState.RegisterToken(value ? JsonTokenType.True : JsonTokenType.False);
|
||||
this.binaryWriter.Write(value ? JsonBinaryEncoding.TypeMarker.True : JsonBinaryEncoding.TypeMarker.False);
|
||||
this.bufferedContexts.Peek().Count++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a null to the internal buffer.
|
||||
/// </summary>
|
||||
public override void WriteNullValue()
|
||||
{
|
||||
this.JsonObjectState.RegisterToken(JsonTokenType.Null);
|
||||
this.binaryWriter.Write(JsonBinaryEncoding.TypeMarker.Null);
|
||||
this.bufferedContexts.Peek().Count++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the result of the JsonWriter.
|
||||
/// </summary>
|
||||
/// <returns>The result of the JsonWriter as an array of bytes.</returns>
|
||||
public override byte[] GetResult()
|
||||
{
|
||||
if (this.bufferedContexts.Count > 1)
|
||||
{
|
||||
throw new JsonNotCompleteException();
|
||||
}
|
||||
|
||||
this.binaryWriter.Flush();
|
||||
long bytesWritten = this.CurrentLength;
|
||||
byte[] result = new byte[bytesWritten];
|
||||
this.binaryWriter.BaseStream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
if (bytesWritten > int.MaxValue)
|
||||
{
|
||||
throw new InvalidOperationException("Can not get back a buffer more than int.MaxValue");
|
||||
}
|
||||
|
||||
this.binaryWriter.BaseStream.Read(result, 0, (int)bytesWritten);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a raw json token to the internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="jsonTokenType">The JsonTokenType of the rawJsonToken</param>
|
||||
/// <param name="rawJsonToken">The raw json token.</param>
|
||||
protected override void WriteRawJsonToken(JsonTokenType jsonTokenType, IReadOnlyList<byte> rawJsonToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private void WriterArrayOrObjectStart(bool isArray)
|
||||
{
|
||||
this.JsonObjectState.RegisterToken(isArray ? JsonTokenType.BeginArray : JsonTokenType.BeginObject);
|
||||
|
||||
// Save the start index
|
||||
this.bufferedContexts.Push(new BeginOffsetAndCount(this.CurrentLength));
|
||||
|
||||
// Assume 2-byte value length; as such, we need to reserve upto 5 bytes (1 byte type marker, 2 byte length, 2 byte count).
|
||||
// We'll adjust this as needed when writing the end of the array/object.
|
||||
this.binaryWriter.Write((byte)0);
|
||||
this.binaryWriter.Write((ushort)0);
|
||||
if (this.serializeCount)
|
||||
{
|
||||
this.binaryWriter.Write((ushort)0);
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteArrayOrObjectEnd(bool isArray)
|
||||
{
|
||||
this.JsonObjectState.RegisterToken(isArray ? JsonTokenType.EndArray : JsonTokenType.EndObject);
|
||||
BeginOffsetAndCount nestedContext = this.bufferedContexts.Pop();
|
||||
|
||||
// Do some math
|
||||
int typeMarkerIndex = (int)nestedContext.Offset;
|
||||
int payloadIndex = typeMarkerIndex + this.reservationSize;
|
||||
int originalCursor = (int)this.CurrentLength;
|
||||
int payloadLength = originalCursor - payloadIndex;
|
||||
int count = (int)nestedContext.Count;
|
||||
|
||||
// Figure out what the typemarker and length should be and do any corrections needed
|
||||
if (count == 0)
|
||||
{
|
||||
// Empty object
|
||||
|
||||
// Move the cursor back
|
||||
this.binaryWriter.BaseStream.Seek(typeMarkerIndex, SeekOrigin.Begin);
|
||||
|
||||
// Write the type marker
|
||||
this.binaryWriter.Write(
|
||||
isArray ? JsonBinaryEncoding.TypeMarker.EmptyArray : JsonBinaryEncoding.TypeMarker.EmptyObject);
|
||||
}
|
||||
else if (count == 1)
|
||||
{
|
||||
// Single-property object
|
||||
|
||||
// Move the buffer back 2 or 4 bytes since we don't need to encode a length
|
||||
byte[] buffer = ((MemoryStream)this.binaryWriter.BaseStream).GetBuffer();
|
||||
Array.Copy(buffer, payloadIndex, buffer, payloadIndex - (TwoByteLength + (this.serializeCount ? TwoByteCount : 0)), payloadLength);
|
||||
|
||||
// Move the cursor back
|
||||
this.binaryWriter.BaseStream.Seek(typeMarkerIndex, SeekOrigin.Begin);
|
||||
|
||||
// Write the type marker
|
||||
this.binaryWriter.Write(
|
||||
isArray ? JsonBinaryEncoding.TypeMarker.SingleItemArray : JsonBinaryEncoding.TypeMarker.SinglePropertyObject);
|
||||
|
||||
// Move the cursor forward
|
||||
this.binaryWriter.BaseStream.Seek(typeMarkerIndex + TypeMarker + payloadLength, SeekOrigin.Begin);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Need to figure out how many bytes to encode the length and the count
|
||||
if (payloadLength <= byte.MaxValue)
|
||||
{
|
||||
// 1 byte length - move the buffer back
|
||||
byte[] buffer = ((MemoryStream)this.binaryWriter.BaseStream).GetBuffer();
|
||||
Array.Copy(buffer, payloadIndex, buffer, payloadIndex - (OneByteLength + (this.serializeCount ? OneByteCount : 0)), payloadLength);
|
||||
|
||||
// Move the cursor back
|
||||
this.binaryWriter.BaseStream.Seek(typeMarkerIndex, SeekOrigin.Begin);
|
||||
|
||||
// Write the type marker
|
||||
if (this.serializeCount)
|
||||
{
|
||||
this.binaryWriter.Write(
|
||||
isArray ? JsonBinaryEncoding.TypeMarker.Array1ByteLengthAndCount : JsonBinaryEncoding.TypeMarker.Object1ByteLengthAndCount);
|
||||
this.binaryWriter.Write((byte)payloadLength);
|
||||
this.binaryWriter.Write((byte)count);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.binaryWriter.Write(
|
||||
isArray ? JsonBinaryEncoding.TypeMarker.Array1ByteLength : JsonBinaryEncoding.TypeMarker.Object1ByteLength);
|
||||
this.binaryWriter.Write((byte)payloadLength);
|
||||
}
|
||||
|
||||
// Move the cursor forward
|
||||
this.binaryWriter.BaseStream.Seek(typeMarkerIndex + TypeMarker + OneByteLength + (this.serializeCount ? OneByteCount : 0) + payloadLength, SeekOrigin.Begin);
|
||||
}
|
||||
else if (payloadLength <= ushort.MaxValue)
|
||||
{
|
||||
// 2 byte length - don't need to move the buffer
|
||||
// Move the cursor back
|
||||
this.binaryWriter.BaseStream.Seek(typeMarkerIndex, SeekOrigin.Begin);
|
||||
|
||||
// Write the type marker
|
||||
if (this.serializeCount)
|
||||
{
|
||||
this.binaryWriter.Write(
|
||||
isArray ? JsonBinaryEncoding.TypeMarker.Array2ByteLengthAndCount : JsonBinaryEncoding.TypeMarker.Object2ByteLengthAndCount);
|
||||
this.binaryWriter.Write((ushort)payloadLength);
|
||||
this.binaryWriter.Write((ushort)count);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.binaryWriter.Write(
|
||||
isArray ? JsonBinaryEncoding.TypeMarker.Array2ByteLength : JsonBinaryEncoding.TypeMarker.Object2ByteLength);
|
||||
this.binaryWriter.Write((ushort)payloadLength);
|
||||
}
|
||||
|
||||
// Move the cursor forward
|
||||
this.binaryWriter.BaseStream.Seek(typeMarkerIndex + TypeMarker + TwoByteLength + (this.serializeCount ? TwoByteCount : 0) + payloadLength, SeekOrigin.Begin);
|
||||
}
|
||||
else
|
||||
{
|
||||
// (payloadLength <= uint.MaxValue)
|
||||
|
||||
// 4 byte length - make space for an extra 2 byte length (and 2 byte count)
|
||||
this.binaryWriter.Write((ushort)0);
|
||||
if (this.serializeCount)
|
||||
{
|
||||
this.binaryWriter.Write((ushort)0);
|
||||
}
|
||||
|
||||
// Move the buffer forward
|
||||
byte[] buffer = ((MemoryStream)this.binaryWriter.BaseStream).GetBuffer();
|
||||
Array.Copy(buffer, payloadIndex, buffer, payloadIndex + TwoByteLength + (this.serializeCount ? TwoByteCount : 0), payloadLength);
|
||||
|
||||
// Move the cursor back
|
||||
this.binaryWriter.BaseStream.Seek(typeMarkerIndex, SeekOrigin.Begin);
|
||||
|
||||
// Write the type marker
|
||||
if (this.serializeCount)
|
||||
{
|
||||
this.binaryWriter.Write(
|
||||
isArray ? JsonBinaryEncoding.TypeMarker.Array4ByteLengthAndCount : JsonBinaryEncoding.TypeMarker.Object4ByteLengthAndCount);
|
||||
this.binaryWriter.Write((uint)payloadLength);
|
||||
this.binaryWriter.Write((uint)count);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.binaryWriter.Write(
|
||||
isArray ? JsonBinaryEncoding.TypeMarker.Array4ByteLength : JsonBinaryEncoding.TypeMarker.Object4ByteLength);
|
||||
this.binaryWriter.Write((uint)payloadLength);
|
||||
}
|
||||
|
||||
// Move the cursor forward
|
||||
this.binaryWriter.BaseStream.Seek(typeMarkerIndex + TypeMarker + FourByteLength + (this.serializeCount ? FourByteCount : 0) + payloadLength, SeekOrigin.Begin);
|
||||
}
|
||||
}
|
||||
|
||||
this.bufferedContexts.Peek().Count++;
|
||||
}
|
||||
|
||||
private bool TryGetEncodedStringTypeMarker(string value, out JsonBinaryEncoding.MultiByteTypeMarker typeMarker)
|
||||
{
|
||||
if (this.TryGetEncodedSystemStringTypeMarker(value, out typeMarker))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.TryGetEncodedUserStringTypeMarker(value, out typeMarker))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool TryGetEncodedUserStringTypeMarker(string value, out JsonBinaryEncoding.MultiByteTypeMarker typeMarker)
|
||||
{
|
||||
typeMarker = new JsonBinaryEncoding.MultiByteTypeMarker();
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool TryGetEncodedSystemStringTypeMarker(string value, out JsonBinaryEncoding.MultiByteTypeMarker typeMarker)
|
||||
{
|
||||
typeMarker = new JsonBinaryEncoding.MultiByteTypeMarker(null);
|
||||
int systemStringId;
|
||||
if (JsonBinaryEncoding.TryGetSystemStringId(value, out systemStringId))
|
||||
{
|
||||
const byte OneByteCount = JsonBinaryEncoding.TypeMarker.SystemString1ByteLengthMax - JsonBinaryEncoding.TypeMarker.SystemString1ByteLengthMin;
|
||||
|
||||
if (systemStringId < OneByteCount)
|
||||
{
|
||||
byte[] typeMarkerBytes = new byte[]
|
||||
{
|
||||
(byte)(JsonBinaryEncoding.TypeMarker.SystemString1ByteLengthMin + (int)systemStringId)
|
||||
};
|
||||
|
||||
typeMarker = new JsonBinaryEncoding.MultiByteTypeMarker(typeMarkerBytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
int twoByteOffset = ((int)systemStringId) - OneByteCount;
|
||||
byte[] typeMarkerBytes = new byte[]
|
||||
{
|
||||
(byte)((twoByteOffset / 0xFF) + JsonBinaryEncoding.TypeMarker.SystemString2ByteLengthMin),
|
||||
(byte)(twoByteOffset % 0xFF),
|
||||
};
|
||||
|
||||
typeMarker = new JsonBinaryEncoding.MultiByteTypeMarker(typeMarkerBytes);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void WriteFieldNameOrString(bool isFieldName, string value)
|
||||
{
|
||||
this.JsonObjectState.RegisterToken(isFieldName ? JsonTokenType.FieldName : JsonTokenType.String);
|
||||
JsonBinaryEncoding.MultiByteTypeMarker multiByteTypeMarker;
|
||||
if (this.TryGetEncodedStringTypeMarker(value, out multiByteTypeMarker))
|
||||
{
|
||||
foreach (byte byteValue in multiByteTypeMarker.Values)
|
||||
{
|
||||
this.binaryWriter.Write(byteValue);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] utf8String = Encoding.UTF8.GetBytes(value);
|
||||
|
||||
// See if the string length can be encoded into a single type marker
|
||||
byte typeMarker = JsonBinaryEncoding.TypeMarker.GetEncodedStringLengthTypeMarker(utf8String.Length);
|
||||
if (JsonBinaryEncoding.TypeMarker.IsValid(typeMarker))
|
||||
{
|
||||
this.binaryWriter.Write(typeMarker);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Just write the type marker and the corresponding length
|
||||
if (utf8String.Length < byte.MaxValue)
|
||||
{
|
||||
this.binaryWriter.Write(JsonBinaryEncoding.TypeMarker.String1ByteLength);
|
||||
this.binaryWriter.Write((byte)utf8String.Length);
|
||||
}
|
||||
else if (utf8String.Length < ushort.MaxValue)
|
||||
{
|
||||
this.binaryWriter.Write(JsonBinaryEncoding.TypeMarker.String2ByteLength);
|
||||
this.binaryWriter.Write((ushort)utf8String.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
// (utf8String.Length < uint.MaxValue)
|
||||
this.binaryWriter.Write(JsonBinaryEncoding.TypeMarker.String4ByteLength);
|
||||
this.binaryWriter.Write((uint)utf8String.Length);
|
||||
}
|
||||
}
|
||||
|
||||
// Finally write the string itself.
|
||||
this.binaryWriter.Write(utf8String);
|
||||
}
|
||||
|
||||
if (!isFieldName)
|
||||
{
|
||||
// If we just wrote a string then increment the count (we don't increment for field names, since we need to wait for the corresponding property value).
|
||||
this.bufferedContexts.Peek().Count++;
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteIntegerInternal(long value)
|
||||
{
|
||||
if (JsonBinaryEncoding.TypeMarker.IsEncodedIntegerLiteral(value))
|
||||
{
|
||||
this.binaryWriter.Write((byte)(JsonBinaryEncoding.TypeMarker.LiteralIntMin + value));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (value >= 0)
|
||||
{
|
||||
// Non-negative Number
|
||||
if (value <= byte.MaxValue)
|
||||
{
|
||||
this.binaryWriter.Write(JsonBinaryEncoding.TypeMarker.UInt8);
|
||||
this.binaryWriter.Write((byte)value);
|
||||
}
|
||||
else if (value <= short.MaxValue)
|
||||
{
|
||||
this.binaryWriter.Write(JsonBinaryEncoding.TypeMarker.Int16);
|
||||
this.binaryWriter.Write((short)value);
|
||||
}
|
||||
else if (value <= int.MaxValue)
|
||||
{
|
||||
this.binaryWriter.Write(JsonBinaryEncoding.TypeMarker.Int32);
|
||||
this.binaryWriter.Write((int)value);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.binaryWriter.Write(JsonBinaryEncoding.TypeMarker.Int64);
|
||||
this.binaryWriter.Write((long)value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Negative Number
|
||||
if (value < int.MinValue)
|
||||
{
|
||||
this.binaryWriter.Write(JsonBinaryEncoding.TypeMarker.Int64);
|
||||
this.binaryWriter.Write((long)value);
|
||||
}
|
||||
else if (value < short.MinValue)
|
||||
{
|
||||
this.binaryWriter.Write(JsonBinaryEncoding.TypeMarker.Int32);
|
||||
this.binaryWriter.Write((int)value);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.binaryWriter.Write(JsonBinaryEncoding.TypeMarker.Int16);
|
||||
this.binaryWriter.Write((short)value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class BeginOffsetAndCount
|
||||
{
|
||||
public BeginOffsetAndCount(long offset)
|
||||
{
|
||||
this.Offset = offset;
|
||||
this.Count = 0;
|
||||
}
|
||||
|
||||
public long Offset { get; }
|
||||
|
||||
public long Count { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,432 @@
|
|||
//-----------------------------------------------------------------------
|
||||
// <copyright file="JsonWriter.JsonTextWriter.cs" company="Microsoft Corporation">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
namespace Microsoft.Azure.Cosmos.Json
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
/// <summary>
|
||||
/// Partial class for the JsonWriter that has a private JsonTextWriter below.
|
||||
/// </summary>
|
||||
internal abstract partial class JsonWriter : IJsonWriter
|
||||
{
|
||||
/// <summary>
|
||||
/// This class is used to build a JSON string.
|
||||
/// It supports our defined IJsonWriter interface.
|
||||
/// It keeps an stack to keep track of scope, and provides error checking using that.
|
||||
/// It has few other variables for error checking
|
||||
/// The user can also provide initial size to reserve string buffer, that will help reduce cost of reallocation.
|
||||
/// It provides error checking based on JSON grammar. It provides escaping for nine characters specified in JSON.
|
||||
/// </summary>
|
||||
private sealed class JsonTextWriter : JsonWriter
|
||||
{
|
||||
private const char ValueSeperatorToken = ':';
|
||||
private const char MemberSeperatorToken = ',';
|
||||
private const char ObjectStartToken = '{';
|
||||
private const char ObjectEndToken = '}';
|
||||
private const char ArrayStartToken = '[';
|
||||
private const char ArrayEndToken = ']';
|
||||
private const char PropertyStartToken = '"';
|
||||
private const char PropertyEndToken = '"';
|
||||
private const char StringStartToken = '"';
|
||||
private const char StringEndToken = '"';
|
||||
|
||||
private const string NotANumber = "NaN";
|
||||
private const string PositiveInfinity = "Infinity";
|
||||
private const string NegativeInfinity = "-Infinity";
|
||||
private const string TrueString = "true";
|
||||
private const string FalseString = "false";
|
||||
private const string NullString = "null";
|
||||
|
||||
private static readonly Dictionary<Encoding, string> ByteOrderMarkDictionary = new Dictionary<Encoding, string>
|
||||
{
|
||||
{ Encoding.UTF8, "\xEF\xBB\xBF" },
|
||||
{ Encoding.Unicode, "\xFF\xFE" },
|
||||
{ Encoding.UTF32, "\xFF\xFE\x00\x00" },
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The internal StreamWriter
|
||||
/// </summary>
|
||||
private readonly StreamWriter streamWriter;
|
||||
|
||||
/// <summary>
|
||||
/// Whether we are writing the first value of an array or object
|
||||
/// </summary>
|
||||
private bool firstValue;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonTextWriter class.
|
||||
/// </summary>
|
||||
/// <param name="encoding">The encoding to use.</param>
|
||||
/// <param name="skipValidation">Whether or not to skip validation</param>
|
||||
public JsonTextWriter(Encoding encoding, bool skipValidation)
|
||||
: base(skipValidation)
|
||||
{
|
||||
this.firstValue = true;
|
||||
this.streamWriter = new StreamWriter(new MemoryStream(), encoding);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the SerializationFormat of the JsonWriter.
|
||||
/// </summary>
|
||||
public override JsonSerializationFormat SerializationFormat
|
||||
{
|
||||
get
|
||||
{
|
||||
return JsonSerializationFormat.Text;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current length of the internal buffer.
|
||||
/// </summary>
|
||||
public override long CurrentLength
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.streamWriter.BaseStream.Position;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the object start symbol to internal buffer.
|
||||
/// </summary>
|
||||
public override void WriteObjectStart()
|
||||
{
|
||||
this.JsonObjectState.RegisterToken(JsonTokenType.BeginObject);
|
||||
this.PrefixMemberSeparator();
|
||||
this.WriteChar(ObjectStartToken);
|
||||
this.firstValue = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the object end symbol to the internal buffer.
|
||||
/// </summary>
|
||||
public override void WriteObjectEnd()
|
||||
{
|
||||
this.JsonObjectState.RegisterToken(JsonTokenType.EndObject);
|
||||
this.WriteChar(ObjectEndToken);
|
||||
|
||||
// We reset firstValue here because we'll need a separator before the next value
|
||||
this.firstValue = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the array start symbol to the internal buffer.
|
||||
/// </summary>
|
||||
public override void WriteArrayStart()
|
||||
{
|
||||
this.JsonObjectState.RegisterToken(JsonTokenType.BeginArray);
|
||||
this.PrefixMemberSeparator();
|
||||
this.WriteChar(ArrayStartToken);
|
||||
this.firstValue = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the array end symbol to the internal buffer.
|
||||
/// </summary>
|
||||
public override void WriteArrayEnd()
|
||||
{
|
||||
this.JsonObjectState.RegisterToken(JsonTokenType.EndArray);
|
||||
this.WriteChar(ArrayEndToken);
|
||||
|
||||
// We reset firstValue here because we'll need a separator before the next value
|
||||
this.firstValue = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a field name to the the internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="fieldName">The name of the field to write.</param>
|
||||
public override void WriteFieldName(string fieldName)
|
||||
{
|
||||
this.JsonObjectState.RegisterToken(JsonTokenType.FieldName);
|
||||
this.PrefixMemberSeparator();
|
||||
|
||||
// no separator after property name
|
||||
this.firstValue = true;
|
||||
|
||||
this.WriteChar(PropertyStartToken);
|
||||
this.WriteEscapedStringToStreamWriter(fieldName, this.streamWriter);
|
||||
this.WriteChar(PropertyEndToken);
|
||||
|
||||
this.WriteChar(ValueSeperatorToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a string to the internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="value">The value of the string to write.</param>
|
||||
public override void WriteStringValue(string value)
|
||||
{
|
||||
this.JsonObjectState.RegisterToken(JsonTokenType.String);
|
||||
this.PrefixMemberSeparator();
|
||||
|
||||
this.WriteChar(StringStartToken);
|
||||
this.WriteEscapedStringToStreamWriter(value, this.streamWriter);
|
||||
this.WriteChar(StringEndToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes an integer to the internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="value">The value of the integer to write.</param>
|
||||
public override void WriteIntValue(long value)
|
||||
{
|
||||
this.JsonObjectState.RegisterToken(JsonTokenType.Number);
|
||||
this.PrefixMemberSeparator();
|
||||
this.streamWriter.Write(value.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a number to the internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="value">The value of the number to write.</param>
|
||||
public override void WriteNumberValue(double value)
|
||||
{
|
||||
// The maximum integer value that can be stored in an IEEE 754 double type w/o losing precision
|
||||
const double MaxFullPrecisionValue = ((long)1) << 53;
|
||||
|
||||
// Check if the number is an integer
|
||||
double truncatedValue = Math.Floor(value);
|
||||
if ((truncatedValue == value) && (value >= -MaxFullPrecisionValue) && (value <= MaxFullPrecisionValue))
|
||||
{
|
||||
// The number does not have any decimals and fits in a 64-bit value
|
||||
this.WriteIntValue((long)value);
|
||||
return;
|
||||
}
|
||||
|
||||
this.JsonObjectState.RegisterToken(JsonTokenType.Number);
|
||||
this.PrefixMemberSeparator();
|
||||
|
||||
if (double.IsNaN(value))
|
||||
{
|
||||
this.WriteChar(StringStartToken);
|
||||
this.streamWriter.Write(NotANumber);
|
||||
this.WriteChar(StringEndToken);
|
||||
}
|
||||
else if (double.IsNegativeInfinity(value))
|
||||
{
|
||||
this.WriteChar(StringStartToken);
|
||||
this.streamWriter.Write(NegativeInfinity);
|
||||
this.WriteChar(StringEndToken);
|
||||
}
|
||||
else if (double.IsPositiveInfinity(value))
|
||||
{
|
||||
this.WriteChar(StringStartToken);
|
||||
this.streamWriter.Write(PositiveInfinity);
|
||||
this.WriteChar(StringEndToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If you require more precision, specify format with the "G17" format specification, which always returns 17 digits of precision,
|
||||
// or "R", which returns 15 digits if the number can be represented with that precision or 17 digits if the number can only be represented with maximum precision.
|
||||
// In some cases, Double values formatted with the "R" standard numeric format string do not successfully round-trip if compiled using the /platform:x64 or /platform:anycpu switches and run on 64-bit systems. To work around this problem, you can format Double values by using the "G17" standard numeric format string.
|
||||
this.streamWriter.Write(value.ToString("R"));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a boolean to the internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="value">The value of the boolean to write.</param>
|
||||
public override void WriteBoolValue(bool value)
|
||||
{
|
||||
this.JsonObjectState.RegisterToken(value ? JsonTokenType.True : JsonTokenType.False);
|
||||
this.PrefixMemberSeparator();
|
||||
|
||||
if (value)
|
||||
{
|
||||
this.streamWriter.Write(TrueString);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.streamWriter.Write(FalseString);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a null to the internal buffer.
|
||||
/// </summary>
|
||||
public override void WriteNullValue()
|
||||
{
|
||||
this.JsonObjectState.RegisterToken(JsonTokenType.Null);
|
||||
this.PrefixMemberSeparator();
|
||||
this.streamWriter.Write(NullString);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the result of the JsonWriter.
|
||||
/// </summary>
|
||||
/// <returns>The result of the JsonWriter as an array of bytes.</returns>
|
||||
public override byte[] GetResult()
|
||||
{
|
||||
// Flush the stream
|
||||
this.streamWriter.Flush();
|
||||
|
||||
// Create a binaryreader to read from the stream
|
||||
BinaryReader binaryReader = new BinaryReader(this.streamWriter.BaseStream);
|
||||
|
||||
// Figure out how many bytes have been written
|
||||
long bytesWritten = this.CurrentLength;
|
||||
|
||||
// Seek to the begining but skip the byte order mark
|
||||
int byteOrderMarkLength = JsonTextWriter.ByteOrderMarkDictionary[this.streamWriter.Encoding].Length;
|
||||
this.streamWriter.BaseStream.Seek(byteOrderMarkLength, SeekOrigin.Begin);
|
||||
|
||||
// Read the entire steam
|
||||
return binaryReader.ReadBytes((int)(bytesWritten - byteOrderMarkLength));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the result of all the writes as a string.
|
||||
/// </summary>
|
||||
/// <returns>The result of all the writes as a string.</returns>
|
||||
public string GetStringResult()
|
||||
{
|
||||
// Flush the stream
|
||||
this.streamWriter.Flush();
|
||||
|
||||
// Create a stream reader to read from the stream
|
||||
StreamReader streamReader = new StreamReader(
|
||||
this.streamWriter.BaseStream,
|
||||
this.streamWriter.Encoding);
|
||||
|
||||
// Seek to the begining
|
||||
this.streamWriter.BaseStream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
// Read the entire stream
|
||||
string stringResult = streamReader.ReadToEnd();
|
||||
return stringResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a raw json token to the internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="jsonTokenType">The JsonTokenType of the rawJsonToken</param>
|
||||
/// <param name="rawJsonToken">The raw json token.</param>
|
||||
protected override void WriteRawJsonToken(JsonTokenType jsonTokenType, IReadOnlyList<byte> rawJsonToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a character to the stream.
|
||||
/// </summary>
|
||||
/// <param name="value">The character to write to the stream.</param>
|
||||
private void WriteChar(char value)
|
||||
{
|
||||
this.streamWriter.Write(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will insert a member separator token if one is needed.
|
||||
/// </summary>
|
||||
private void PrefixMemberSeparator()
|
||||
{
|
||||
if (!this.firstValue)
|
||||
{
|
||||
this.WriteChar(MemberSeperatorToken);
|
||||
}
|
||||
|
||||
this.firstValue = false;
|
||||
}
|
||||
|
||||
private bool RequiresEscapeSequence(char value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case '\\':
|
||||
case '"':
|
||||
case '/':
|
||||
case '\b':
|
||||
case '\f':
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '\t':
|
||||
return true;
|
||||
default:
|
||||
return value < ' ';
|
||||
}
|
||||
}
|
||||
|
||||
private char GetHexDigit(byte value)
|
||||
{
|
||||
if (value > 0xF)
|
||||
{
|
||||
throw new ArgumentException("value must be less than 0xF");
|
||||
}
|
||||
|
||||
return (value < 10) ? (char)('0' + value) : (char)('a' + value - 10);
|
||||
}
|
||||
|
||||
private void WriteEscapedStringToStreamWriter(string value, StreamWriter streamWriter)
|
||||
{
|
||||
int readOffset = 0;
|
||||
while (readOffset != value.Length)
|
||||
{
|
||||
if (!this.RequiresEscapeSequence(value[readOffset]))
|
||||
{
|
||||
// Just write the character as is
|
||||
this.streamWriter.Write(value[readOffset++]);
|
||||
}
|
||||
else
|
||||
{
|
||||
char characterToEscape = value[readOffset++];
|
||||
char escapeSequence = default(char);
|
||||
switch (characterToEscape)
|
||||
{
|
||||
case '\\':
|
||||
escapeSequence = '\\';
|
||||
break;
|
||||
case '"':
|
||||
escapeSequence = '"';
|
||||
break;
|
||||
case '/':
|
||||
escapeSequence = '/';
|
||||
break;
|
||||
case '\b':
|
||||
escapeSequence = 'b';
|
||||
break;
|
||||
case '\f':
|
||||
escapeSequence = 'f';
|
||||
break;
|
||||
case '\n':
|
||||
escapeSequence = 'n';
|
||||
break;
|
||||
case '\r':
|
||||
escapeSequence = 'r';
|
||||
break;
|
||||
case '\t':
|
||||
escapeSequence = 't';
|
||||
break;
|
||||
}
|
||||
|
||||
if (escapeSequence >= ' ')
|
||||
{
|
||||
// We got a special character
|
||||
streamWriter.Write('\\');
|
||||
streamWriter.Write(escapeSequence);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We got a control character (U+0000 through U+001F).
|
||||
streamWriter.Write('\\');
|
||||
streamWriter.Write('u');
|
||||
streamWriter.Write(this.GetHexDigit((byte)(((byte)characterToEscape >> 12) & 0xF)));
|
||||
streamWriter.Write(this.GetHexDigit((byte)(((byte)characterToEscape >> 8) & 0xF)));
|
||||
streamWriter.Write(this.GetHexDigit((byte)(((byte)characterToEscape >> 4) & 0xF)));
|
||||
streamWriter.Write(this.GetHexDigit((byte)(((byte)characterToEscape) & 0xF)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,373 @@
|
|||
//-----------------------------------------------------------------------
|
||||
// <copyright file="JsonWriter.cs" company="Microsoft Corporation">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
namespace Microsoft.Azure.Cosmos.Json
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.Azure.Documents;
|
||||
|
||||
/// <summary>
|
||||
/// Base abstract class for JSON writers.
|
||||
/// The writer defines methods that allow for writing a JSON encoded value to a buffer.
|
||||
/// </summary>
|
||||
internal abstract partial class JsonWriter : IJsonWriter
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="JsonObjectState"/>
|
||||
/// </summary>
|
||||
protected readonly JsonObjectState JsonObjectState;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to skip validation.
|
||||
/// </summary>
|
||||
protected readonly bool SkipValidation;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JsonWriter class.
|
||||
/// </summary>
|
||||
/// <param name="skipValidation">Whether or not to skip validation.</param>
|
||||
protected JsonWriter(bool skipValidation)
|
||||
{
|
||||
this.JsonObjectState = new JsonObjectState(false);
|
||||
this.SkipValidation = skipValidation;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the SerializationFormat of the JsonWriter.
|
||||
/// </summary>
|
||||
public abstract JsonSerializationFormat SerializationFormat { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current length of the internal buffer.
|
||||
/// </summary>
|
||||
public abstract long CurrentLength { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a JsonTextWriter that can write in a particular encoding
|
||||
/// </summary>
|
||||
/// <param name="encoding">The encoding to write in.</param>
|
||||
/// <param name="skipValidation">Whether or not to skip validation</param>
|
||||
/// <returns>A JsonWriter that can write in a particular JsonSerializationFormat</returns>
|
||||
public static IJsonWriter Create(Encoding encoding, bool skipValidation = false)
|
||||
{
|
||||
if (encoding != Encoding.UTF8 && encoding != Encoding.Unicode && encoding != Encoding.UTF32)
|
||||
{
|
||||
throw new ArgumentException("Text encoding must be UTF8, UTF16 / Unicode or UTF32");
|
||||
}
|
||||
|
||||
return new JsonTextWriter(encoding, skipValidation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a JsonWriter that can write in a particular JsonSerializationFormat (utf8 if text)
|
||||
/// </summary>
|
||||
/// <param name="jsonSerializationFormat">The JsonSerializationFormat of the writer.</param>
|
||||
/// <param name="skipValidation">Whether or not to skip validation</param>
|
||||
/// <returns>A JsonWriter that can write in a particular JsonSerializationFormat</returns>
|
||||
public static IJsonWriter Create(JsonSerializationFormat jsonSerializationFormat, bool skipValidation = false)
|
||||
{
|
||||
switch (jsonSerializationFormat)
|
||||
{
|
||||
case JsonSerializationFormat.Text:
|
||||
return new JsonTextWriter(Encoding.UTF8, skipValidation);
|
||||
case JsonSerializationFormat.Binary:
|
||||
return new JsonBinaryWriter(skipValidation, false);
|
||||
default:
|
||||
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, RMResources.UnexpectedJsonSerializationFormat, jsonSerializationFormat));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the object start symbol to internal buffer.
|
||||
/// </summary>
|
||||
public abstract void WriteObjectStart();
|
||||
|
||||
/// <summary>
|
||||
/// Writes the object end symbol to the internal buffer.
|
||||
/// </summary>
|
||||
public abstract void WriteObjectEnd();
|
||||
|
||||
/// <summary>
|
||||
/// Writes the array start symbol to the internal buffer.
|
||||
/// </summary>
|
||||
public abstract void WriteArrayStart();
|
||||
|
||||
/// <summary>
|
||||
/// Writes the array end symbol to the internal buffer.
|
||||
/// </summary>
|
||||
public abstract void WriteArrayEnd();
|
||||
|
||||
/// <summary>
|
||||
/// Writes a field name to the the internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="fieldName">The name of the field to write.</param>
|
||||
public abstract void WriteFieldName(string fieldName);
|
||||
|
||||
/// <summary>
|
||||
/// Writes a string to the internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="value">The value of the string to write.</param>
|
||||
public abstract void WriteStringValue(string value);
|
||||
|
||||
/// <summary>
|
||||
/// Writes an integer to the internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="value">The value of the integer to write.</param>
|
||||
public abstract void WriteIntValue(long value);
|
||||
|
||||
/// <summary>
|
||||
/// Writes a number to the internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="value">The value of the number to write.</param>
|
||||
public abstract void WriteNumberValue(double value);
|
||||
|
||||
/// <summary>
|
||||
/// Writes a boolean to the internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="value">The value of the boolean to write.</param>
|
||||
public abstract void WriteBoolValue(bool value);
|
||||
|
||||
/// <summary>
|
||||
/// Writes a null to the internal buffer.
|
||||
/// </summary>
|
||||
public abstract void WriteNullValue();
|
||||
|
||||
/// <summary>
|
||||
/// Writes current token from a json reader to the internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="jsonReader">The JsonReader to the get the current token from.</param>
|
||||
public void WriteCurrentToken(IJsonReader jsonReader)
|
||||
{
|
||||
if (jsonReader == null)
|
||||
{
|
||||
throw new ArgumentNullException("jsonReader can not be null");
|
||||
}
|
||||
|
||||
// For now short circuit this to false until we figure out how to optimize this.
|
||||
bool sameFormat = jsonReader.SerializationFormat == this.SerializationFormat && false;
|
||||
|
||||
JsonTokenType jsonTokenType = jsonReader.CurrentTokenType;
|
||||
switch (jsonTokenType)
|
||||
{
|
||||
case JsonTokenType.NotStarted:
|
||||
break;
|
||||
case JsonTokenType.BeginArray:
|
||||
this.WriteArrayStart();
|
||||
break;
|
||||
case JsonTokenType.EndArray:
|
||||
this.WriteArrayEnd();
|
||||
break;
|
||||
case JsonTokenType.BeginObject:
|
||||
this.WriteObjectStart();
|
||||
break;
|
||||
case JsonTokenType.EndObject:
|
||||
this.WriteObjectEnd();
|
||||
break;
|
||||
case JsonTokenType.True:
|
||||
this.WriteBoolValue(true);
|
||||
break;
|
||||
case JsonTokenType.False:
|
||||
this.WriteBoolValue(false);
|
||||
break;
|
||||
case JsonTokenType.Null:
|
||||
this.WriteNullValue();
|
||||
break;
|
||||
case JsonTokenType.String:
|
||||
case JsonTokenType.Number:
|
||||
case JsonTokenType.FieldName:
|
||||
{
|
||||
if (sameFormat)
|
||||
{
|
||||
IReadOnlyList<byte> bufferedRawJson = jsonReader.GetBufferedRawJsonToken();
|
||||
this.WriteRawJsonToken(jsonTokenType, bufferedRawJson);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (jsonTokenType == JsonTokenType.Number)
|
||||
{
|
||||
double number = jsonReader.GetNumberValue();
|
||||
this.WriteNumberValue(number);
|
||||
}
|
||||
else
|
||||
{
|
||||
string value = jsonReader.GetStringValue();
|
||||
if (jsonTokenType == JsonTokenType.FieldName)
|
||||
{
|
||||
this.WriteFieldName(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.WriteStringValue(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw new ArgumentException($"Unexpected JsonTokenType: {jsonTokenType}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes every token from the JsonReader to the internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="jsonReader">The JsonReader to get the tokens from.</param>
|
||||
public void WriteAll(IJsonReader jsonReader)
|
||||
{
|
||||
if (jsonReader == null)
|
||||
{
|
||||
throw new ArgumentNullException("jsonReader can not be null");
|
||||
}
|
||||
|
||||
while (jsonReader.Read())
|
||||
{
|
||||
this.WriteCurrentToken(jsonReader);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a fragment of a json to the internal buffer
|
||||
/// </summary>
|
||||
/// <param name="jsonFragment">A section of a valid json</param>
|
||||
public void WriteJsonFragment(IReadOnlyList<byte> jsonFragment)
|
||||
{
|
||||
if (jsonFragment == null)
|
||||
{
|
||||
throw new ArgumentNullException("jsonFragment can not be null");
|
||||
}
|
||||
|
||||
IJsonReader jsonReader = JsonReader.Create(new MemoryStream(jsonFragment.ToArray()));
|
||||
this.WriteAll(jsonReader);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a json node to the internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="jsonNavigator">The navigator to use to navigate the node</param>
|
||||
/// <param name="jsonNavigatorNode">The node to write.</param>
|
||||
public void WriteJsonNode(IJsonNavigator jsonNavigator, IJsonNavigatorNode jsonNavigatorNode)
|
||||
{
|
||||
if (jsonNavigator == null)
|
||||
{
|
||||
throw new ArgumentNullException($"{nameof(jsonNavigator)} can not be null");
|
||||
}
|
||||
|
||||
if (jsonNavigatorNode == null)
|
||||
{
|
||||
throw new ArgumentNullException($"{nameof(jsonNavigatorNode)} can not be null");
|
||||
}
|
||||
|
||||
// For now short circuit this to false until we figure out how to optimize this.
|
||||
bool sameFormat = jsonNavigator.SerializationFormat == this.SerializationFormat && false;
|
||||
|
||||
JsonNodeType jsonNodeType = jsonNavigator.GetNodeType(jsonNavigatorNode);
|
||||
|
||||
// See if we can write the node without looking at it's value
|
||||
switch (jsonNodeType)
|
||||
{
|
||||
case JsonNodeType.Null:
|
||||
this.WriteNullValue();
|
||||
return;
|
||||
case JsonNodeType.False:
|
||||
this.WriteBoolValue(false);
|
||||
return;
|
||||
case JsonNodeType.True:
|
||||
this.WriteBoolValue(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// If the navigator has the same format as this writer then we try to retrieve the node raw JSON
|
||||
IReadOnlyList<byte> bufferedRawJson;
|
||||
if (sameFormat && jsonNavigator.TryGetBufferedRawJson(jsonNavigatorNode, out bufferedRawJson))
|
||||
{
|
||||
// Token type really doesn't make any difference other than whether this is a field name
|
||||
JsonTokenType jsonTokenType = (jsonNodeType == JsonNodeType.FieldName ? JsonTokenType.FieldName : JsonTokenType.Null);
|
||||
this.WriteRawJsonToken(jsonTokenType, bufferedRawJson);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Either the formats did not match or we couldn't retrieve the buffered raw JSON
|
||||
switch (jsonNodeType)
|
||||
{
|
||||
case JsonNodeType.Number:
|
||||
double numberValue = jsonNavigator.GetNumberValue(jsonNavigatorNode);
|
||||
this.WriteNumberValue(numberValue);
|
||||
break;
|
||||
|
||||
case JsonNodeType.String:
|
||||
case JsonNodeType.FieldName:
|
||||
bool fieldName = jsonNodeType == JsonNodeType.FieldName;
|
||||
IReadOnlyList<byte> bufferedStringValue;
|
||||
if (jsonNavigator.TryGetBufferedStringValue(jsonNavigatorNode, out bufferedStringValue))
|
||||
{
|
||||
if (fieldName)
|
||||
{
|
||||
this.WriteRawJsonToken(JsonTokenType.FieldName, bufferedStringValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.WriteRawJsonToken(JsonTokenType.String, bufferedStringValue);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string value = jsonNavigator.GetStringValue(jsonNavigatorNode);
|
||||
if (fieldName)
|
||||
{
|
||||
this.WriteFieldName(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.WriteStringValue(value);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case JsonNodeType.Array:
|
||||
this.WriteArrayStart();
|
||||
foreach (IJsonNavigatorNode arrayItem in jsonNavigator.GetArrayItems(jsonNavigatorNode))
|
||||
{
|
||||
this.WriteJsonNode(jsonNavigator, arrayItem);
|
||||
}
|
||||
this.WriteArrayEnd();
|
||||
break;
|
||||
|
||||
case JsonNodeType.Object:
|
||||
this.WriteObjectStart();
|
||||
foreach (ObjectProperty objectProperty in jsonNavigator.GetObjectProperties(jsonNavigatorNode))
|
||||
{
|
||||
this.WriteJsonNode(jsonNavigator, objectProperty.NameNode);
|
||||
this.WriteJsonNode(jsonNavigator, objectProperty.ValueNode);
|
||||
}
|
||||
this.WriteObjectEnd();
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentException($"Unexpected JsonNodeType: {jsonNodeType}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the result of the JsonWriter.
|
||||
/// </summary>
|
||||
/// <returns>The result of the JsonWriter as an array of bytes.</returns>
|
||||
public abstract byte[] GetResult();
|
||||
|
||||
/// <summary>
|
||||
/// Writes a raw json token to the internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="jsonTokenType">The JsonTokenType of the rawJsonToken</param>
|
||||
/// <param name="rawJsonToken">The raw json token.</param>
|
||||
protected abstract void WriteRawJsonToken(JsonTokenType jsonTokenType, IReadOnlyList<byte> rawJsonToken);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
//-----------------------------------------------------------------------
|
||||
// <copyright file="LittleEndianBinaryReader.cs" company="Microsoft Corporation">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
namespace Microsoft.Azure.Cosmos.Json
|
||||
{
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
/// <summary>
|
||||
/// A BinaryReader that can read binary that has little endian byte ordering for a client that can be run a both a big endian and little endian machine.
|
||||
/// </summary>
|
||||
internal sealed class LittleEndianBinaryReader : BinaryReader
|
||||
{
|
||||
/// <summary>
|
||||
/// Flag used to determine if the machine is a little endian machine.
|
||||
/// </summary>
|
||||
private readonly bool isLittleEndian;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the LittleEndianBinaryReader class based on the specified stream and using UTF-8 encoding.
|
||||
/// </summary>
|
||||
/// <param name="input">The input stream.</param>
|
||||
public LittleEndianBinaryReader(Stream input)
|
||||
: this(input, Encoding.UTF8)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the LittleEndianBinaryReader class based on the specified stream and character encoding.
|
||||
/// </summary>
|
||||
/// <param name="input">The input stream.</param>
|
||||
/// <param name="encoding">The character encoding to use.</param>
|
||||
public LittleEndianBinaryReader(Stream input, Encoding encoding)
|
||||
: this(input, encoding, false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the LittleEndianBinaryReader class based on the specified stream and character encoding, and optionally leaves the stream open.
|
||||
/// </summary>
|
||||
/// <param name="input">The input stream.</param>
|
||||
/// <param name="encoding">The character encoding to use.</param>
|
||||
/// <param name="leaveOpen">true to leave the stream open after the System.IO.BinaryReader object is disposed; otherwise, false.</param>
|
||||
public LittleEndianBinaryReader(Stream input, Encoding encoding, bool leaveOpen)
|
||||
: this(input, encoding, leaveOpen, BitConverter.IsLittleEndian)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the LittleEndianBinaryReader class for testing purposes, since we don't want the user to be able to tell us what the endianness of the machine is.
|
||||
/// Thus this constructor is private.
|
||||
/// </summary>
|
||||
/// <param name="input">The input stream.</param>
|
||||
/// <param name="encoding">The character encoding to use.</param>
|
||||
/// <param name="leaveOpen">true to leave the stream open after the System.IO.BinaryReader object is disposed; otherwise, false.</param>
|
||||
/// <param name="isLittleEndian">Whether the machine is a little endian machine</param>
|
||||
private LittleEndianBinaryReader(Stream input, Encoding encoding, bool leaveOpen, bool isLittleEndian)
|
||||
: base(input, encoding, leaveOpen)
|
||||
{
|
||||
this.isLittleEndian = isLittleEndian;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a Boolean value from the current stream and advances the current position of the stream by one byte.
|
||||
/// </summary>
|
||||
/// <returns>true if the byte is nonzero; otherwise, false.</returns>
|
||||
public override bool ReadBoolean()
|
||||
{
|
||||
// Bools are just 1 byte so we can just return what the base class does.
|
||||
return base.ReadBoolean();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the next byte from the current stream and advances the current position of the stream by one byte.
|
||||
/// </summary>
|
||||
/// <returns>The next byte read from the current stream.</returns>
|
||||
public override byte ReadByte()
|
||||
{
|
||||
// A single byte has no byte order so we can just pass it down to the base class
|
||||
return base.ReadByte();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the next decimal from the current stream and advances the current position of the stream by 16 bytes.
|
||||
/// </summary>
|
||||
/// <returns>The next decimal read from the current stream.</returns>
|
||||
public override decimal ReadDecimal()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads an 8-byte floating point value from the current stream and advances the current position of the stream by eight bytes.
|
||||
/// </summary>
|
||||
/// <returns>An 8-byte floating point value read from the current stream.</returns>
|
||||
public override double ReadDouble()
|
||||
{
|
||||
return this.isLittleEndian ? base.ReadDouble() : ByteOrder.Reverse(base.ReadDouble());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 2-byte signed integer from the current stream and advances the current position of the stream by two bytes.
|
||||
/// </summary>
|
||||
/// <returns> A 2-byte signed integer read from the current stream.</returns>
|
||||
public override short ReadInt16()
|
||||
{
|
||||
return this.isLittleEndian ? base.ReadInt16() : ByteOrder.Reverse(base.ReadInt16());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 4-byte signed integer from the current stream and advances the current position of the stream by four bytes.
|
||||
/// </summary>
|
||||
/// <returns>A 4-byte signed integer read from the current stream.</returns>
|
||||
public override int ReadInt32()
|
||||
{
|
||||
return this.isLittleEndian ? base.ReadInt32() : ByteOrder.Reverse(base.ReadInt32());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads an 8-byte signed integer from the current stream and advances the current position of the stream by eight bytes.
|
||||
/// </summary>
|
||||
/// <returns>An 8-byte signed integer read from the current stream.</returns>
|
||||
public override long ReadInt64()
|
||||
{
|
||||
return this.isLittleEndian ? base.ReadInt64() : ByteOrder.Reverse(base.ReadInt64());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a signed byte from this stream and advances the current position of the stream by one byte.
|
||||
/// </summary>
|
||||
/// <returns>A signed byte read from the current stream.</returns>
|
||||
public override sbyte ReadSByte()
|
||||
{
|
||||
// A single byte has no byte order.
|
||||
return base.ReadSByte();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 4-byte floating point value from the current stream and advances the current position of the stream by four bytes.
|
||||
/// </summary>
|
||||
/// <returns>A 4-byte floating point value read from the current stream.</returns>
|
||||
public override float ReadSingle()
|
||||
{
|
||||
return this.isLittleEndian ? base.ReadSingle() : ByteOrder.Reverse(base.ReadSingle());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a string from the current stream. The string is prefixed with the length, encoded as an integer seven bits at a time.
|
||||
/// </summary>
|
||||
/// <returns>The string being read.</returns>
|
||||
public override string ReadString()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 2-byte unsigned integer from the current stream and advances the position of the stream by two bytes.
|
||||
/// </summary>
|
||||
/// <returns>A 2-byte unsigned integer from the current stream</returns>
|
||||
public override ushort ReadUInt16()
|
||||
{
|
||||
return this.isLittleEndian ? base.ReadUInt16() : ByteOrder.Reverse(base.ReadUInt16());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 4-byte unsigned integer from the current stream and advances the position of the stream by four bytes.
|
||||
/// </summary>
|
||||
/// <returns>A 4-byte unsigned integer read from this stream.</returns>
|
||||
public override uint ReadUInt32()
|
||||
{
|
||||
return this.isLittleEndian ? base.ReadUInt32() : ByteOrder.Reverse(base.ReadUInt32());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads an 8-byte unsigned integer from the current stream and advances the position of the stream by eight bytes.
|
||||
/// </summary>
|
||||
/// <returns>An 8-byte unsigned integer read from this stream.</returns>
|
||||
public override ulong ReadUInt64()
|
||||
{
|
||||
return this.isLittleEndian ? base.ReadUInt64() : ByteOrder.Reverse(base.ReadUInt64());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
//-----------------------------------------------------------------------
|
||||
// <copyright file="ObjectProperty.cs" company="Microsoft Corporation">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
namespace Microsoft.Azure.Cosmos.Json
|
||||
{
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// Struct to hold the property name and property value for an object property.
|
||||
/// </summary>
|
||||
internal struct ObjectProperty
|
||||
{
|
||||
/// <summary>
|
||||
/// The IJsonNavigatorNode to the node that holds the object property name.
|
||||
/// </summary>
|
||||
public readonly IJsonNavigatorNode NameNode;
|
||||
|
||||
/// <summary>
|
||||
/// The IJsonNavigatorNode to the node that holds the object property value.
|
||||
/// </summary>
|
||||
public readonly IJsonNavigatorNode ValueNode;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ObjectProperty struct.
|
||||
/// </summary>
|
||||
/// <param name="nameNode">The IJsonNavigatorNode to the node that holds the object property name.</param>
|
||||
/// <param name="valueNode">The IJsonNavigatorNode to the node that holds the object property value.</param>
|
||||
public ObjectProperty(IJsonNavigatorNode nameNode, IJsonNavigatorNode valueNode)
|
||||
{
|
||||
if (nameNode == null)
|
||||
{
|
||||
throw new ArgumentNullException("nameNode");
|
||||
}
|
||||
|
||||
if (valueNode == null)
|
||||
{
|
||||
throw new ArgumentNullException("valueNode");
|
||||
}
|
||||
|
||||
this.NameNode = nameNode;
|
||||
this.ValueNode = valueNode;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@ namespace Microsoft.Azure.Cosmos.Linq
|
|||
using System.Reflection;
|
||||
using Microsoft.Azure.Cosmos;
|
||||
using static Microsoft.Azure.Cosmos.Linq.FromParameterBindings;
|
||||
using Microsoft.Azure.Documents;
|
||||
|
||||
internal abstract class BuiltinFunctionVisitor
|
||||
{
|
||||
|
|
|
@ -15,12 +15,15 @@ namespace Microsoft.Azure.Cosmos.Linq
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Globalization;
|
||||
using Microsoft.Azure.Documents;
|
||||
using Microsoft.Azure.Documents.Collections;
|
||||
using Microsoft.Azure.Documents.Routing;
|
||||
|
||||
/// <summary>
|
||||
/// Provides interface for historical change feed.
|
||||
/// </summary>
|
||||
/// <typeparam name="TResource">Source Resource Type (e.g. Document)</typeparam>
|
||||
internal sealed class ChangeFeedQuery<TResource> : IDocumentQuery<TResource> where TResource : CosmosResource, new()
|
||||
internal sealed class ChangeFeedQuery<TResource> : IDocumentQuery<TResource> where TResource : new()
|
||||
{
|
||||
#region Fields
|
||||
private const string IfNoneMatchAllHeaderValue = "*"; // This means start from current.
|
||||
|
|
|
@ -8,6 +8,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
using System.Linq;
|
||||
using Microsoft.Azure.Cosmos.Linq;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Documents;
|
||||
|
||||
internal partial class DocumentClient
|
||||
{
|
||||
|
@ -25,11 +26,11 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// ]]>
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// <seealso cref="CosmosDatabaseSettings"/>
|
||||
/// <seealso cref="Database"/>
|
||||
/// <seealso cref="Microsoft.Azure.Cosmos.Linq.IDocumentQuery"/>
|
||||
public IOrderedQueryable<CosmosDatabaseSettings> CreateDatabaseQuery(FeedOptions feedOptions = null)
|
||||
public IOrderedQueryable<Database> CreateDatabaseQuery(FeedOptions feedOptions = null)
|
||||
{
|
||||
return new DocumentQuery<CosmosDatabaseSettings>(this, ResourceType.Database, typeof(CosmosDatabaseSettings), Paths.Databases_Root, feedOptions);
|
||||
return new DocumentQuery<Database>(this, ResourceType.Database, typeof(Database), Paths.Databases_Root, feedOptions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -47,7 +48,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// </code>
|
||||
/// </example>
|
||||
/// <remarks>Refer to https://msdn.microsoft.com/en-us/library/azure/dn782250.aspx and http://azure.microsoft.com/documentation/articles/documentdb-sql-query/ for syntax and examples.</remarks>
|
||||
/// <seealso cref="CosmosDatabaseSettings"/>
|
||||
/// <seealso cref="Database"/>
|
||||
/// <seealso cref="Microsoft.Azure.Cosmos.Linq.IDocumentQuery"/>
|
||||
public IQueryable<dynamic> CreateDatabaseQuery(string sqlExpression, FeedOptions feedOptions = null)
|
||||
{
|
||||
|
@ -72,11 +73,11 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// </code>
|
||||
/// </example>
|
||||
/// <remarks>Refer to https://msdn.microsoft.com/en-us/library/azure/dn782250.aspx and http://azure.microsoft.com/documentation/articles/documentdb-sql-query/ for syntax and examples.</remarks>
|
||||
/// <seealso cref="CosmosDatabaseSettings"/>
|
||||
/// <seealso cref="Database"/>
|
||||
/// <seealso cref="Microsoft.Azure.Cosmos.Linq.IDocumentQuery"/>
|
||||
public IQueryable<dynamic> CreateDatabaseQuery(SqlQuerySpec querySpec, FeedOptions feedOptions = null)
|
||||
{
|
||||
return new DocumentQuery<CosmosDatabaseSettings>(this, ResourceType.Database, typeof(CosmosDatabaseSettings), Paths.Databases_Root, feedOptions).AsSQL(querySpec);
|
||||
return new DocumentQuery<Database>(this, ResourceType.Database, typeof(Database), Paths.Databases_Root, feedOptions).AsSQL(querySpec);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -85,10 +86,11 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// </summary>
|
||||
/// <param name="feedOptions">The options for processing the query results feed.</param>
|
||||
/// <returns>the query result set.</returns>
|
||||
internal IDocumentQuery<CosmosDatabaseSettings> CreateDatabaseChangeFeedQuery(ChangeFeedOptions feedOptions)
|
||||
internal IDocumentQuery<Database> CreateDatabaseChangeFeedQuery(ChangeFeedOptions feedOptions)
|
||||
{
|
||||
ValidateChangeFeedOptionsForNotPartitionedResource(feedOptions);
|
||||
return new ChangeFeedQuery<CosmosDatabaseSettings>(this, ResourceType.Database, null, feedOptions);
|
||||
throw new NotImplementedException();
|
||||
////ValidateChangeFeedOptionsForNotPartitionedResource(feedOptions);
|
||||
////return new Document.ChangeFeedQuery<Database>(this, ResourceType.Database, null, feedOptions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -105,11 +107,11 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// ]]>
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// <seealso cref="CosmosContainerSettings"/>
|
||||
/// <seealso cref="DocumentCollection"/>
|
||||
/// <seealso cref="Microsoft.Azure.Cosmos.Linq.IDocumentQuery"/>
|
||||
public IOrderedQueryable<CosmosContainerSettings> CreateDocumentCollectionQuery(string databaseLink, FeedOptions feedOptions = null)
|
||||
public IOrderedQueryable<DocumentCollection> CreateDocumentCollectionQuery(string databaseLink, FeedOptions feedOptions = null)
|
||||
{
|
||||
return new DocumentQuery<CosmosContainerSettings>(this, ResourceType.Collection, typeof(CosmosContainerSettings), databaseLink, feedOptions);
|
||||
return new DocumentQuery<DocumentCollection>(this, ResourceType.Collection, typeof(DocumentCollection), databaseLink, feedOptions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -128,7 +130,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// </code>
|
||||
/// </example>
|
||||
/// <remarks>Refer to https://msdn.microsoft.com/en-us/library/azure/dn782250.aspx and http://azure.microsoft.com/documentation/articles/documentdb-sql-query/ for syntax and examples.</remarks>
|
||||
/// <seealso cref="CosmosContainerSettings"/>
|
||||
/// <seealso cref="DocumentCollection"/>
|
||||
/// <seealso cref="Microsoft.Azure.Cosmos.Linq.IDocumentQuery"/>
|
||||
public IQueryable<dynamic> CreateDocumentCollectionQuery(string databaseLink, string sqlExpression, FeedOptions feedOptions = null)
|
||||
{
|
||||
|
@ -153,11 +155,11 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// </code>
|
||||
/// </example>
|
||||
/// <remarks>Refer to https://msdn.microsoft.com/en-us/library/azure/dn782250.aspx and http://azure.microsoft.com/documentation/articles/documentdb-sql-query/ for syntax and examples.</remarks>
|
||||
/// <seealso cref="CosmosContainerSettings"/>
|
||||
/// <seealso cref="DocumentCollection"/>
|
||||
/// <seealso cref="Microsoft.Azure.Cosmos.Linq.IDocumentQuery"/>
|
||||
public IQueryable<dynamic> CreateDocumentCollectionQuery(string databaseLink, SqlQuerySpec querySpec, FeedOptions feedOptions = null)
|
||||
{
|
||||
return new DocumentQuery<CosmosContainerSettings>(this, ResourceType.Collection, typeof(CosmosContainerSettings), databaseLink, feedOptions).AsSQL(querySpec);
|
||||
return new DocumentQuery<DocumentCollection>(this, ResourceType.Collection, typeof(DocumentCollection), databaseLink, feedOptions).AsSQL(querySpec);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -167,15 +169,16 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// <param name="databaseLink">Specifies the database to read collections from.</param>
|
||||
/// <param name="feedOptions">Specifies the options for processing the query results feed.</param>
|
||||
/// <returns>the query result set.</returns>
|
||||
internal IDocumentQuery<CosmosContainerSettings> CreateDocumentCollectionChangeFeedQuery(string databaseLink, ChangeFeedOptions feedOptions)
|
||||
internal IDocumentQuery<DocumentCollection> CreateDocumentCollectionChangeFeedQuery(string databaseLink, ChangeFeedOptions feedOptions)
|
||||
{
|
||||
if(string.IsNullOrEmpty(databaseLink))
|
||||
{
|
||||
throw new ArgumentException(nameof(databaseLink));
|
||||
}
|
||||
throw new NotImplementedException();
|
||||
////if(string.IsNullOrEmpty(databaseLink))
|
||||
////{
|
||||
//// throw new ArgumentException(nameof(databaseLink));
|
||||
////}
|
||||
|
||||
ValidateChangeFeedOptionsForNotPartitionedResource(feedOptions);
|
||||
return new ChangeFeedQuery<CosmosContainerSettings>(this, ResourceType.Collection, databaseLink, feedOptions);
|
||||
////ValidateChangeFeedOptionsForNotPartitionedResource(feedOptions);
|
||||
////return new ChangeFeedQuery<DocumentCollection>(this, ResourceType.Collection, databaseLink, feedOptions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -192,11 +195,11 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// ]]>
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// <seealso cref="CosmosStoredProcedureSettings"/>
|
||||
/// <seealso cref="StoredProcedure"/>
|
||||
/// <seealso cref="Microsoft.Azure.Cosmos.Linq.IDocumentQuery"/>
|
||||
public IOrderedQueryable<CosmosStoredProcedureSettings> CreateStoredProcedureQuery(string collectionLink, FeedOptions feedOptions = null)
|
||||
public IOrderedQueryable<StoredProcedure> CreateStoredProcedureQuery(string collectionLink, FeedOptions feedOptions = null)
|
||||
{
|
||||
return new DocumentQuery<CosmosStoredProcedureSettings>(this, ResourceType.StoredProcedure, typeof(CosmosStoredProcedureSettings), collectionLink, feedOptions);
|
||||
return new DocumentQuery<StoredProcedure>(this, ResourceType.StoredProcedure, typeof(StoredProcedure), collectionLink, feedOptions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -215,7 +218,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// </code>
|
||||
/// </example>
|
||||
/// <remarks>Refer to https://msdn.microsoft.com/en-us/library/azure/dn782250.aspx and http://azure.microsoft.com/documentation/articles/documentdb-sql-query/ for syntax and examples.</remarks>
|
||||
/// <seealso cref="CosmosStoredProcedureSettings"/>
|
||||
/// <seealso cref="StoredProcedure"/>
|
||||
public IQueryable<dynamic> CreateStoredProcedureQuery(string collectionLink, string sqlExpression, FeedOptions feedOptions = null)
|
||||
{
|
||||
return this.CreateStoredProcedureQuery(collectionLink, new SqlQuerySpec(sqlExpression), feedOptions);
|
||||
|
@ -239,10 +242,10 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// </code>
|
||||
/// </example>
|
||||
/// <remarks>Refer to https://msdn.microsoft.com/en-us/library/azure/dn782250.aspx and http://azure.microsoft.com/documentation/articles/documentdb-sql-query/ for syntax and examples.</remarks>
|
||||
/// <seealso cref="CosmosStoredProcedureSettings"/>
|
||||
/// <seealso cref="StoredProcedure"/>
|
||||
public IQueryable<dynamic> CreateStoredProcedureQuery(string collectionLink, SqlQuerySpec querySpec, FeedOptions feedOptions = null)
|
||||
{
|
||||
return new DocumentQuery<CosmosStoredProcedureSettings>(this, ResourceType.StoredProcedure, typeof(CosmosStoredProcedureSettings), collectionLink, feedOptions).AsSQL(querySpec);
|
||||
return new DocumentQuery<StoredProcedure>(this, ResourceType.StoredProcedure, typeof(StoredProcedure), collectionLink, feedOptions).AsSQL(querySpec);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -259,11 +262,11 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// ]]>
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// <seealso cref="CosmosTriggerSettings"/>
|
||||
/// <seealso cref="Trigger"/>
|
||||
/// <seealso cref="Microsoft.Azure.Cosmos.Linq.IDocumentQuery"/>
|
||||
public IOrderedQueryable<CosmosTriggerSettings> CreateTriggerQuery(string collectionLink, FeedOptions feedOptions = null)
|
||||
public IOrderedQueryable<Trigger> CreateTriggerQuery(string collectionLink, FeedOptions feedOptions = null)
|
||||
{
|
||||
return new DocumentQuery<CosmosTriggerSettings>(this, ResourceType.Trigger, typeof(CosmosTriggerSettings), collectionLink, feedOptions);
|
||||
return new DocumentQuery<Trigger>(this, ResourceType.Trigger, typeof(Trigger), collectionLink, feedOptions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -282,7 +285,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// </code>
|
||||
/// </example>
|
||||
/// <remarks>Refer to https://msdn.microsoft.com/en-us/library/azure/dn782250.aspx and http://azure.microsoft.com/documentation/articles/documentdb-sql-query/ for syntax and examples.</remarks>
|
||||
/// <seealso cref="CosmosTriggerSettings"/>
|
||||
/// <seealso cref="Trigger"/>
|
||||
/// <seealso cref="Microsoft.Azure.Cosmos.Linq.IDocumentQuery"/>
|
||||
public IQueryable<dynamic> CreateTriggerQuery(string collectionLink, string sqlExpression, FeedOptions feedOptions = null)
|
||||
{
|
||||
|
@ -307,11 +310,11 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// </code>
|
||||
/// </example>
|
||||
/// <remarks>Refer to https://msdn.microsoft.com/en-us/library/azure/dn782250.aspx and http://azure.microsoft.com/documentation/articles/documentdb-sql-query/ for syntax and examples.</remarks>
|
||||
/// <seealso cref="CosmosTriggerSettings"/>
|
||||
/// <seealso cref="Trigger"/>
|
||||
/// <seealso cref="Microsoft.Azure.Cosmos.Linq.IDocumentQuery"/>
|
||||
public IQueryable<dynamic> CreateTriggerQuery(string collectionLink, SqlQuerySpec querySpec, FeedOptions feedOptions = null)
|
||||
{
|
||||
return new DocumentQuery<CosmosTriggerSettings>(this, ResourceType.Trigger, typeof(CosmosTriggerSettings), collectionLink, feedOptions).AsSQL(querySpec);
|
||||
return new DocumentQuery<Trigger>(this, ResourceType.Trigger, typeof(Trigger), collectionLink, feedOptions).AsSQL(querySpec);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -328,11 +331,11 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// ]]>
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// <seealso cref="CosmosUserDefinedFunctionSettings"/>
|
||||
/// <seealso cref="UserDefinedFunction"/>
|
||||
/// <seealso cref="Microsoft.Azure.Cosmos.Linq.IDocumentQuery"/>
|
||||
public IOrderedQueryable<CosmosUserDefinedFunctionSettings> CreateUserDefinedFunctionQuery(string collectionLink, FeedOptions feedOptions = null)
|
||||
public IOrderedQueryable<UserDefinedFunction> CreateUserDefinedFunctionQuery(string collectionLink, FeedOptions feedOptions = null)
|
||||
{
|
||||
return new DocumentQuery<CosmosUserDefinedFunctionSettings>(this, ResourceType.UserDefinedFunction, typeof(CosmosUserDefinedFunctionSettings), collectionLink, feedOptions);
|
||||
return new DocumentQuery<UserDefinedFunction>(this, ResourceType.UserDefinedFunction, typeof(UserDefinedFunction), collectionLink, feedOptions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -351,7 +354,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// </code>
|
||||
/// </example>
|
||||
/// <remarks>Refer to https://msdn.microsoft.com/en-us/library/azure/dn782250.aspx and http://azure.microsoft.com/documentation/articles/documentdb-sql-query/ for syntax and examples.</remarks>
|
||||
/// <seealso cref="CosmosUserDefinedFunctionSettings"/>
|
||||
/// <seealso cref="UserDefinedFunction"/>
|
||||
/// <seealso cref="Microsoft.Azure.Cosmos.Linq.IDocumentQuery"/>
|
||||
public IQueryable<dynamic> CreateUserDefinedFunctionQuery(string collectionLink, string sqlExpression, FeedOptions feedOptions = null)
|
||||
{
|
||||
|
@ -376,11 +379,11 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// </code>
|
||||
/// </example>
|
||||
/// <remarks>Refer to https://msdn.microsoft.com/en-us/library/azure/dn782250.aspx and http://azure.microsoft.com/documentation/articles/documentdb-sql-query/ for syntax and examples.</remarks>
|
||||
/// <seealso cref="CosmosUserDefinedFunctionSettings"/>
|
||||
/// <seealso cref="UserDefinedFunction"/>
|
||||
/// <seealso cref="Microsoft.Azure.Cosmos.Linq.IDocumentQuery"/>
|
||||
public IQueryable<dynamic> CreateUserDefinedFunctionQuery(string collectionLink, SqlQuerySpec querySpec, FeedOptions feedOptions = null)
|
||||
{
|
||||
return new DocumentQuery<CosmosUserDefinedFunctionSettings>(this, ResourceType.UserDefinedFunction, typeof(CosmosUserDefinedFunctionSettings), collectionLink, feedOptions).AsSQL(querySpec);
|
||||
return new DocumentQuery<UserDefinedFunction>(this, ResourceType.UserDefinedFunction, typeof(UserDefinedFunction), collectionLink, feedOptions).AsSQL(querySpec);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1091,13 +1094,14 @@ namespace Microsoft.Azure.Cosmos
|
|||
/// <returns>the query result set.</returns>
|
||||
internal IDocumentQuery<UserDefinedType> CreateUserDefinedTypeChangeFeedQuery(string databaseLink, ChangeFeedOptions feedOptions)
|
||||
{
|
||||
if (string.IsNullOrEmpty(databaseLink))
|
||||
{
|
||||
throw new ArgumentException(nameof(databaseLink));
|
||||
}
|
||||
throw new NotImplementedException();
|
||||
////if (string.IsNullOrEmpty(databaseLink))
|
||||
////{
|
||||
//// throw new ArgumentException(nameof(databaseLink));
|
||||
////}
|
||||
|
||||
ValidateChangeFeedOptionsForNotPartitionedResource(feedOptions);
|
||||
return new ChangeFeedQuery<UserDefinedType>(this, ResourceType.UserDefinedType, databaseLink, feedOptions);
|
||||
////ValidateChangeFeedOptionsForNotPartitionedResource(feedOptions);
|
||||
////return new ChangeFeedQuery<UserDefinedType>(this, ResourceType.UserDefinedType, databaseLink, feedOptions);
|
||||
}
|
||||
#endregion Query Methods
|
||||
|
||||
|
|
|
@ -16,6 +16,8 @@ namespace Microsoft.Azure.Cosmos.Linq
|
|||
using Microsoft.Azure.Cosmos.CosmosElements;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Cosmos.Query;
|
||||
using Microsoft.Azure.Documents;
|
||||
using Microsoft.Azure.Documents.Collections;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ namespace Microsoft.Azure.Cosmos.Linq
|
|||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using Microsoft.Azure.Documents;
|
||||
|
||||
internal static class DocumentQueryEvaluator
|
||||
{
|
||||
|
|
|
@ -7,6 +7,7 @@ namespace Microsoft.Azure.Cosmos.Linq
|
|||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Documents;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an exception from the Azure Cosmos DB service queries.
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace Microsoft.Azure.Cosmos.Linq
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Cosmos.Query;
|
||||
using Microsoft.Azure.Documents;
|
||||
|
||||
internal interface IDocumentQueryProvider : IQueryProvider
|
||||
{
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Cosmos.Query;
|
||||
using Microsoft.Azure.Documents;
|
||||
|
||||
/// <summary>
|
||||
/// This class provides extension methods for converting a <see cref="System.Linq.IQueryable{T}"/> object to a <see cref="Microsoft.Azure.Cosmos.Linq.IDocumentQuery{T}"/> object.
|
||||
|
|
Двоичные данные
Microsoft.Azure.Cosmos/src/Linq/ExpressionToSQL.cs
Двоичные данные
Microsoft.Azure.Cosmos/src/Linq/ExpressionToSQL.cs
Двоичный файл не отображается.
|
@ -12,6 +12,7 @@ namespace Microsoft.Azure.Cosmos.Linq
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.Serialization;
|
||||
using Microsoft.Azure.Documents;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
internal static class TypeSystem
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
namespace Microsoft.Azure.Cosmos
|
||||
{
|
||||
using Microsoft.Azure.Cosmos.Collections;
|
||||
using Microsoft.Azure.Documents.Collections;
|
||||
using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<Copyright>© Microsoft Corporation. All rights reserved.</Copyright>
|
||||
<NeutralLanguage>en-US</NeutralLanguage>
|
||||
<ClientVersion>3.0.0.9-preview</ClientVersion>
|
||||
<DirectVersion>3.0.0.9-preview</DirectVersion>
|
||||
<DirectVersion>3.0.0.20-preview</DirectVersion>
|
||||
<Version Condition=" '$(IsNightly)' == '1' ">$(ClientVersion)-nightly$(CurrentDate)</Version>
|
||||
<Version Condition=" '$(IsNightly)' == '0' Or '$(IsNightly)' == '' ">$(ClientVersion)</Version>
|
||||
<FileVersion>$(VersionPrefix)</FileVersion>
|
||||
|
@ -26,7 +26,7 @@
|
|||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<GenerateDocumentationFile>false</GenerateDocumentationFile>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<ShippingScope>External</ShippingScope>
|
||||
<SigningType>Product</SigningType>
|
||||
|
@ -40,7 +40,7 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup Condition=" '$(SignAssembly)' == 'true' ">
|
||||
<PackageReference Include="Microsoft.Azure.Cosmos.Direct" Version="$(DirectVersion)" />
|
||||
</ItemGroup>
|
||||
|
@ -48,38 +48,18 @@
|
|||
<ItemGroup Condition=" '$(SignAssembly)' != 'true' ">
|
||||
<PackageReference Include="Microsoft.Azure.Cosmos.Direct.MyGet" Version="$(DirectVersion)" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="RuntimePerfCounters.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net461' ">
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.configuration" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.ServiceModel" />
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.XML" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
|
||||
<PackageReference Include="System.Configuration.ConfigurationManager" Version="4.5.0" />
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Configuration.ConfigurationManager" Version="4.5.0" />
|
||||
<PackageReference Include="System.ServiceModel.Primitives" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<DefineConstants>DOCDBCLIENT</DefineConstants>
|
||||
<DefineConstants>$(DefineConstants);DOCDBCLIENT;NETSTANDARD20</DefineConstants>
|
||||
<DefineConstants Condition=" '$(SignAssembly)' == 'true' ">$(DefineConstants);SignAssembly</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(TargetFramework)' == 'net461' ">
|
||||
<DefineConstants>$(DefineConstants);NETFX</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
|
||||
<DefineConstants>$(DefineConstants);NETSTANDARD20</DefineConstants>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
|
|
@ -9,6 +9,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.Cosmos.Common;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Documents;
|
||||
|
||||
internal class NullRequestSigner : IRequestSigner
|
||||
{
|
||||
|
|
|
@ -1,72 +0,0 @@
|
|||
//------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------
|
||||
|
||||
namespace Microsoft.Azure.Cosmos
|
||||
{
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
|
||||
internal sealed class OfferFeedResource : CosmosResource, IEnumerable<Offer>
|
||||
{
|
||||
private static string CollectionName
|
||||
{
|
||||
get
|
||||
{
|
||||
return typeof(Offer).Name + "s";
|
||||
}
|
||||
}
|
||||
|
||||
public OfferFeedResource()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.InnerCollection.Count;
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return this.InnerCollection.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator<Offer> IEnumerable<Offer>.GetEnumerator()
|
||||
{
|
||||
return this.InnerCollection.GetEnumerator();
|
||||
}
|
||||
|
||||
internal Collection<Offer> InnerCollection
|
||||
{
|
||||
get
|
||||
{
|
||||
Collection<Offer> collection = base.GetObjectCollection<Offer>(
|
||||
OfferFeedResource.CollectionName,
|
||||
typeof(Offer),
|
||||
this.AltLink,
|
||||
OfferTypeResolver.ResponseOfferTypeResolver);
|
||||
if (collection == null)
|
||||
{
|
||||
collection = new Collection<Offer>();
|
||||
base.SetObjectCollection(OfferFeedResource.CollectionName, collection);
|
||||
}
|
||||
return collection;
|
||||
}
|
||||
set
|
||||
{
|
||||
base.SetObjectCollection(OfferFeedResource.CollectionName, value);
|
||||
}
|
||||
}
|
||||
|
||||
internal override void OnSave()
|
||||
{
|
||||
base.SetValue(Constants.Properties.Count, this.InnerCollection.Count);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@ namespace Microsoft.Azure.Cosmos
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.Cosmos.Common;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Documents;
|
||||
|
||||
internal sealed class PartitionKeyMismatchRetryPolicy : IDocumentClientRetryPolicy
|
||||
{
|
||||
|
|
|
@ -6,6 +6,7 @@ namespace Microsoft.Azure.Cosmos.Query
|
|||
{
|
||||
using System;
|
||||
using Microsoft.Azure.Cosmos.CosmosElements;
|
||||
using Microsoft.Azure.Documents;
|
||||
|
||||
internal struct AggregateItem
|
||||
{
|
||||
|
|
|
@ -8,7 +8,8 @@ namespace Microsoft.Azure.Cosmos.Query.Aggregation
|
|||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Cosmos;
|
||||
using Microsoft.Azure.Documents;
|
||||
using Microsoft.Azure.Cosmos.CosmosElements;
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
//-----------------------------------------------------------------------
|
||||
namespace Microsoft.Azure.Cosmos.Query.Aggregation
|
||||
{
|
||||
using Microsoft.Azure.Cosmos.CosmosElements;
|
||||
using System;
|
||||
using Microsoft.Azure.Cosmos.CosmosElements;
|
||||
|
||||
/// <summary>
|
||||
/// Concrete implementation of IAggregator that can take the global min/max from the local min/max of multiple partitions and continuations.
|
||||
|
|
|
@ -9,6 +9,7 @@ namespace Microsoft.Azure.Cosmos.Query.Aggregation
|
|||
using System.Globalization;
|
||||
using Microsoft.Azure.Cosmos.CosmosElements;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Documents;
|
||||
|
||||
/// <summary>
|
||||
/// Concrete implementation of IAggregator that can take the global sum from the local sum of multiple partitions and continuations.
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace Microsoft.Azure.Cosmos.Collections.Generic
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Documents;
|
||||
|
||||
/// <summary>
|
||||
/// Provides awaitable and bounding capabilities for thread-safe collections that implement IProducerConsumerCollection<T>.
|
||||
|
|
|
@ -6,6 +6,7 @@ namespace Microsoft.Azure.Cosmos.Query
|
|||
{
|
||||
using System;
|
||||
using Microsoft.Azure.Cosmos.Routing;
|
||||
using Microsoft.Azure.Documents.Routing;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -20,6 +20,9 @@ namespace Microsoft.Azure.Cosmos.Query
|
|||
using Microsoft.Azure.Cosmos.Collections;
|
||||
using Microsoft.Azure.Cosmos.CosmosElements;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Documents;
|
||||
using Microsoft.Azure.Documents.Collections;
|
||||
using Microsoft.Azure.Documents.Routing;
|
||||
using Newtonsoft.Json;
|
||||
using ParallelQuery;
|
||||
using Routing;
|
||||
|
|
|
@ -17,6 +17,9 @@ namespace Microsoft.Azure.Cosmos.Query
|
|||
using Microsoft.Azure.Cosmos.CosmosElements;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Cosmos.Routing;
|
||||
using Microsoft.Azure.Documents;
|
||||
using Microsoft.Azure.Documents.Collections;
|
||||
using Microsoft.Azure.Documents.Routing;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace Microsoft.Azure.Cosmos.Query
|
|||
using System.Text;
|
||||
using Microsoft.Azure.Cosmos.CosmosElements;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Documents;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -10,6 +10,8 @@ namespace Microsoft.Azure.Cosmos.Query
|
|||
using System.Text;
|
||||
using Microsoft.Azure.Cosmos.CosmosElements;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Documents;
|
||||
using Microsoft.Azure.Documents.Routing;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Routing;
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ namespace Microsoft.Azure.Cosmos.Query
|
|||
using Collections.Generic;
|
||||
using Microsoft.Azure.Cosmos.CosmosElements;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Documents;
|
||||
using Routing;
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -5,13 +5,12 @@
|
|||
namespace Microsoft.Azure.Cosmos.Query
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.Cosmos.Common;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Cosmos.Routing;
|
||||
using System.Linq;
|
||||
using Microsoft.Azure.Documents;
|
||||
|
||||
internal sealed class DocumentQueryClient : IDocumentQueryClient
|
||||
{
|
||||
|
@ -121,7 +120,7 @@ namespace Microsoft.Azure.Cosmos.Query
|
|||
|
||||
public async Task<ConsistencyLevel> GetDefaultConsistencyLevelAsync()
|
||||
{
|
||||
return await this.innerClient.GetDefaultConsistencyLevelAsync();
|
||||
return (ConsistencyLevel)await this.innerClient.GetDefaultConsistencyLevelAsync();
|
||||
}
|
||||
|
||||
public async Task<ConsistencyLevel?> GetDesiredConsistencyLevelAsync()
|
||||
|
|
|
@ -23,6 +23,9 @@ namespace Microsoft.Azure.Cosmos.Query
|
|||
using Microsoft.Azure.Cosmos.Linq;
|
||||
using Microsoft.Azure.Cosmos.Routing;
|
||||
using Newtonsoft.Json;
|
||||
using Microsoft.Azure.Documents;
|
||||
using Microsoft.Azure.Documents.Collections;
|
||||
using Microsoft.Azure.Documents.Routing;
|
||||
|
||||
internal abstract class DocumentQueryExecutionContextBase : IDocumentQueryExecutionContext
|
||||
{
|
||||
|
@ -187,11 +190,11 @@ namespace Microsoft.Azure.Cosmos.Query
|
|||
{
|
||||
INameValueCollection requestHeaders = new StringKeyValueCollection();
|
||||
|
||||
ConsistencyLevel defaultConsistencyLevel = await this.client.GetDefaultConsistencyLevelAsync();
|
||||
ConsistencyLevel? desiredConsistencyLevel = await this.client.GetDesiredConsistencyLevelAsync();
|
||||
Cosmos.ConsistencyLevel defaultConsistencyLevel = (Cosmos.ConsistencyLevel)(await this.client.GetDefaultConsistencyLevelAsync());
|
||||
Cosmos.ConsistencyLevel? desiredConsistencyLevel = (Cosmos.ConsistencyLevel?)await this.client.GetDesiredConsistencyLevelAsync();
|
||||
if (!string.IsNullOrEmpty(feedOptions.SessionToken) && !ReplicatedResourceClient.IsReadingFromMaster(this.resourceTypeEnum, OperationType.ReadFeed))
|
||||
{
|
||||
if (defaultConsistencyLevel == ConsistencyLevel.Session || (desiredConsistencyLevel.HasValue && desiredConsistencyLevel.Value == ConsistencyLevel.Session))
|
||||
if (defaultConsistencyLevel == Cosmos.ConsistencyLevel.Session || (desiredConsistencyLevel.HasValue && desiredConsistencyLevel.Value == Cosmos.ConsistencyLevel.Session))
|
||||
{
|
||||
// Query across partitions is not supported today. Master resources (for e.g., database)
|
||||
// can span across partitions, whereas server resources (viz: collection, document and attachment)
|
||||
|
@ -249,7 +252,7 @@ namespace Microsoft.Azure.Cosmos.Query
|
|||
|
||||
if (this.feedOptions.ConsistencyLevel.HasValue)
|
||||
{
|
||||
await this.client.EnsureValidOverwrite(feedOptions.ConsistencyLevel.Value);
|
||||
await this.client.EnsureValidOverwrite((Documents.ConsistencyLevel)feedOptions.ConsistencyLevel.Value);
|
||||
requestHeaders.Set(HttpConstants.HttpHeaders.ConsistencyLevel, this.feedOptions.ConsistencyLevel.Value.ToString());
|
||||
}
|
||||
else if (desiredConsistencyLevel.HasValue)
|
||||
|
@ -553,8 +556,8 @@ namespace Microsoft.Azure.Cosmos.Query
|
|||
|
||||
private DocumentServiceRequest CreateReadFeedDocumentServiceRequest(INameValueCollection requestHeaders)
|
||||
{
|
||||
if (this.resourceTypeEnum == Microsoft.Azure.Cosmos.Internal.ResourceType.Database
|
||||
|| this.resourceTypeEnum == Microsoft.Azure.Cosmos.Internal.ResourceType.Offer)
|
||||
if (this.resourceTypeEnum == Documents.ResourceType.Database
|
||||
|| this.resourceTypeEnum == Documents.ResourceType.Offer)
|
||||
{
|
||||
return DocumentServiceRequest.Create(
|
||||
OperationType.ReadFeed,
|
||||
|
@ -670,7 +673,7 @@ namespace Microsoft.Azure.Cosmos.Query
|
|||
{
|
||||
switch (resourceType)
|
||||
{
|
||||
case Internal.ResourceType.Collection:
|
||||
case Documents.ResourceType.Collection:
|
||||
return "DocumentCollections";
|
||||
default:
|
||||
return resourceType.ToResourceTypeString() + "s";
|
||||
|
|
|
@ -17,6 +17,8 @@ namespace Microsoft.Azure.Cosmos.Query
|
|||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Cosmos.Query.ParallelQuery;
|
||||
using Microsoft.Azure.Cosmos.Routing;
|
||||
using Microsoft.Azure.Documents;
|
||||
using Microsoft.Azure.Documents.Routing;
|
||||
|
||||
/// <summary>
|
||||
/// Factory class for creating the appropriate DocumentQueryExecutionContext for the provided type of query.
|
||||
|
|
|
@ -17,6 +17,8 @@ namespace Microsoft.Azure.Cosmos.Query.ExecutionComponent
|
|||
using Microsoft.Azure.Cosmos.CosmosElements;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Cosmos.Query.Aggregation;
|
||||
using Microsoft.Azure.Documents;
|
||||
using Microsoft.Azure.Documents.Collections;
|
||||
|
||||
/// <summary>
|
||||
/// Execution component that is able to aggregate local aggregates from multiple continuations and partitions.
|
||||
|
|
|
@ -13,6 +13,7 @@ namespace Microsoft.Azure.Cosmos.Query.ExecutionComponent
|
|||
using Microsoft.Azure.Cosmos;
|
||||
using Microsoft.Azure.Cosmos.CosmosElements;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Documents;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace Microsoft.Azure.Cosmos.Query.ExecutionComponent
|
|||
using Microsoft.Azure.Cosmos;
|
||||
using Microsoft.Azure.Cosmos.CosmosElements;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Documents;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
internal sealed class SkipDocumentQueryExecutionComponent : DocumentQueryExecutionComponentBase
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace Microsoft.Azure.Cosmos.Query.ExecutionComponent
|
|||
using Microsoft.Azure.Cosmos;
|
||||
using Microsoft.Azure.Cosmos.CosmosElements;
|
||||
using Microsoft.Azure.Cosmos.Internal;
|
||||
using Microsoft.Azure.Documents;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
internal sealed class TakeDocumentQueryExecutionComponent : DocumentQueryExecutionComponentBase
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче