/
QueryRequestOptions.cs
281 lines (244 loc) · 12.3 KB
/
QueryRequestOptions.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace Microsoft.Azure.Cosmos
{
using System;
using System.Globalization;
using System.Text;
using Microsoft.Azure.Cosmos.CosmosElements;
using Microsoft.Azure.Cosmos.Query.Core;
using Microsoft.Azure.Cosmos.Query.Core.ExecutionContext;
using Microsoft.Azure.Documents;
/// <summary>
/// The Cosmos query request options
/// </summary>
public class QueryRequestOptions : RequestOptions
{
/// <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 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>
public bool? EnableScanInQuery { 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 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>
public int? MaxBufferedItemCount { get; set; }
/// <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.
/// This is a maximum. Query can return 0 items in the page.
/// </remarks>
public int? MaxItemCount { 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 will be executed serially with no-parallelism
/// </value>
public int? MaxConcurrency { get; set; }
/// <summary>
/// Gets or sets the <see cref="Cosmos.PartitionKey"/> for the current request in the Azure Cosmos DB service.
/// </summary>
/// <remarks>
/// Only applicable to Item operations
/// </remarks>
public PartitionKey? PartitionKey { get; set; }
/// <summary>
/// Gets or sets the consistency level required for the request 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"/>
/// <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>
public ConsistencyLevel? ConsistencyLevel
{
get => this.BaseConsistencyLevel;
set => this.BaseConsistencyLevel = value;
}
/// <summary>
/// Gets or sets the token for use with session consistency in the Azure Cosmos DB service.
/// </summary>
/// <value>
/// The token for use with session consistency.
/// </value>
///
/// <remarks>
/// One of the <see cref="ConsistencyLevel"/> for Azure Cosmos DB is Session. In fact, this is the default level applied to accounts.
/// <para>
/// When working with Session consistency, each new write request to Azure Cosmos DB is assigned a new SessionToken.
/// The DocumentClient will use this token internally with each read/query request to ensure that the set consistency level is maintained.
///
/// <para>
/// In some scenarios you need to manage this Session yourself;
/// Consider a web application with multiple nodes, each node will have its own instance of <see cref="DocumentClient"/>
/// If you wanted these nodes to participate in the same session (to be able read your own writes consistently across web tiers)
/// you would have to send the SessionToken from <see cref="QueryResponse{T}"/> of the write action on one node
/// to the client tier, using a cookie or some other mechanism, and have that token flow back to the web tier for subsequent reads.
/// If you are using a round-robin load balancer which does not maintain session affinity between requests, such as the Azure Load Balancer,
/// the read could potentially land on a different node to the write request, where the session was created.
/// </para>
///
/// <para>
/// If you do not flow the Azure Cosmos DB SessionToken across as described above you could end up with inconsistent read results for a period of time.
/// </para>
///
/// </para>
/// </remarks>
public string SessionToken { get; set; }
internal CosmosElement CosmosElementContinuationToken { get; set; }
internal string StartId { get; set; }
internal string EndId { get; set; }
internal EnumerationDirection? EnumerationDirection { get; set; }
internal CosmosSerializationFormatOptions CosmosSerializationFormatOptions { get; set; }
internal ExecutionEnvironment? ExecutionEnvironment { get; set; }
internal bool? ReturnResultsInDeterministicOrder { get; set; }
internal TestInjections TestSettings { get; set; }
/// <summary>
/// Fill the CosmosRequestMessage headers with the set properties
/// </summary>
/// <param name="request">The <see cref="RequestMessage"/></param>
internal override void PopulateRequestOptions(RequestMessage request)
{
if (this.PartitionKey != null && request.ResourceType != ResourceType.Document)
{
throw new ArgumentException($"{nameof(this.PartitionKey)} can only be set for item operations");
}
// Cross partition is only applicable to item operations.
if (this.PartitionKey == null && !this.IsEffectivePartitionKeyRouting && request.ResourceType == ResourceType.Document)
{
request.Headers.Add(HttpConstants.HttpHeaders.EnableCrossPartitionQuery, bool.TrueString);
}
RequestOptions.SetSessionToken(request, this.SessionToken);
// Flow the pageSize only when we are not doing client eval
if (this.MaxItemCount.HasValue)
{
request.Headers.Add(HttpConstants.HttpHeaders.PageSize, this.MaxItemCount.ToString());
}
if (this.MaxConcurrency.HasValue && this.MaxConcurrency > 0)
{
request.Headers.Add(HttpConstants.HttpHeaders.ParallelizeCrossPartitionQuery, bool.TrueString);
}
if (this.EnableScanInQuery.HasValue && this.EnableScanInQuery.Value)
{
request.Headers.Add(HttpConstants.HttpHeaders.EnableScanInQuery, bool.TrueString);
}
if (this.EnableLowPrecisionOrderBy != null)
{
request.Headers.Add(HttpConstants.HttpHeaders.EnableLowPrecisionOrderBy, this.EnableLowPrecisionOrderBy.ToString());
}
if (this.ResponseContinuationTokenLimitInKb != null)
{
request.Headers.Add(HttpConstants.HttpHeaders.ResponseContinuationTokenLimitInKB, this.ResponseContinuationTokenLimitInKb.ToString());
}
if (this.CosmosSerializationFormatOptions != null)
{
request.Headers.Add(HttpConstants.HttpHeaders.ContentSerializationFormat, this.CosmosSerializationFormatOptions.ContentSerializationFormat);
}
if (this.StartId != null)
{
request.Headers.Set(HttpConstants.HttpHeaders.StartId, Convert.ToBase64String(Encoding.UTF8.GetBytes(this.StartId)));
}
if (this.EndId != null)
{
request.Headers.Set(HttpConstants.HttpHeaders.EndId, Convert.ToBase64String(Encoding.UTF8.GetBytes(this.EndId)));
}
if (this.StartId != null || this.EndId != null)
{
request.Headers.Set(HttpConstants.HttpHeaders.ReadFeedKeyType, ReadFeedKeyType.ResourceId.ToString());
}
if (this.EnumerationDirection.HasValue)
{
request.Headers.Set(HttpConstants.HttpHeaders.EnumerationDirection, this.EnumerationDirection.Value.ToString());
}
request.Headers.Add(HttpConstants.HttpHeaders.PopulateQueryMetrics, bool.TrueString);
base.PopulateRequestOptions(request);
}
internal QueryRequestOptions Clone()
{
QueryRequestOptions queryRequestOptions = new QueryRequestOptions
{
IfMatchEtag = this.IfMatchEtag,
IfNoneMatchEtag = this.IfNoneMatchEtag,
MaxItemCount = this.MaxItemCount,
ResponseContinuationTokenLimitInKb = this.ResponseContinuationTokenLimitInKb,
EnableScanInQuery = this.EnableScanInQuery,
EnableLowPrecisionOrderBy = this.EnableLowPrecisionOrderBy,
MaxBufferedItemCount = this.MaxBufferedItemCount,
SessionToken = this.SessionToken,
ConsistencyLevel = this.ConsistencyLevel,
MaxConcurrency = this.MaxConcurrency,
PartitionKey = this.PartitionKey,
CosmosSerializationFormatOptions = this.CosmosSerializationFormatOptions,
Properties = this.Properties,
IsEffectivePartitionKeyRouting = this.IsEffectivePartitionKeyRouting,
CosmosElementContinuationToken = this.CosmosElementContinuationToken,
};
return queryRequestOptions;
}
internal static void FillContinuationToken(
RequestMessage request,
string continuationToken)
{
if (!string.IsNullOrWhiteSpace(continuationToken))
{
request.Headers.ContinuationToken = continuationToken;
}
}
internal static void FillMaxItemCount(
RequestMessage request,
int? maxItemCount)
{
if (maxItemCount != null && maxItemCount.HasValue)
{
request.Headers.Add(HttpConstants.HttpHeaders.PageSize, maxItemCount.Value.ToString(CultureInfo.InvariantCulture));
}
}
}
}