-
Notifications
You must be signed in to change notification settings - Fork 477
/
ContainerProperties.cs
765 lines (683 loc) · 31.3 KB
/
ContainerProperties.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
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace Microsoft.Azure.Cosmos
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Microsoft.Azure.Documents;
using Microsoft.Azure.Documents.Routing;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
/// <summary>
/// Represents a document container in the Azure Cosmos DB service. A container is a named logical container for documents.
/// </summary>
/// <remarks>
/// A database may contain zero or more named containers and each container consists of zero or more JSON documents.
/// Being schema-free, the documents in a container do not need to share the same structure or fields. Since containers are application resources,
/// they can be authorized using either the master key or resource keys.
/// </remarks>
/// <seealso href="https://docs.microsoft.com/azure/cosmos-db/databases-containers-items"/>
/// <example>
/// The example below creates a new partitioned container with 50000 Request-per-Unit throughput.
/// The partition key is the first level 'country' property in all the documents within this container.
/// <code language="c#">
/// <![CDATA[
/// Container container = await client.GetDatabase("dbName").Containers.CreateAsync("MyCollection", "/country", 50000);
/// ContainerProperties containerProperties = container.Resource;
/// ]]>
/// </code>
/// </example>
/// <example>
/// The example below creates a new container with a custom indexing policy.
/// <code language="c#">
/// <![CDATA[
/// ContainerProperties containerProperties = new ContainerProperties("MyCollection", "/country");
/// containerProperties.IndexingPolicy.Automatic = true;
/// containerProperties.IndexingPolicy.IndexingMode = IndexingMode.Consistent;
///
/// CosmosContainerResponse containerCreateResponse = await client.GetDatabase("dbName").CreateContainerAsync(containerProperties, 50000);
/// ContainerProperties createdContainerProperties = containerCreateResponse.Container;
/// ]]>
/// </code>
/// </example>
/// <example>
/// The example below deletes this container.
/// <code language="c#">
/// <![CDATA[
/// Container container = client.GetDatabase("dbName").Containers["MyCollection"];
/// await container.DeleteAsync();
/// ]]>
/// </code>
/// </example>
/// <seealso cref="Microsoft.Azure.Cosmos.IndexingPolicy"/>
/// <seealso cref="Microsoft.Azure.Cosmos.UniqueKeyPolicy"/>
public class ContainerProperties
{
private static readonly char[] partitionKeyTokenDelimeter = new char[] { '/' };
[JsonProperty(PropertyName = Constants.Properties.ChangeFeedPolicy, NullValueHandling = NullValueHandling.Ignore)]
private ChangeFeedPolicy changeFeedPolicyInternal;
[JsonProperty(PropertyName = Constants.Properties.IndexingPolicy, NullValueHandling = NullValueHandling.Ignore)]
private IndexingPolicy indexingPolicyInternal;
// TODO: update spatial properties to Constants.Properties.* after the new direct package is released
[JsonProperty(PropertyName = "geospatialConfig", NullValueHandling = NullValueHandling.Ignore)]
private GeospatialConfig geospatialConfigInternal;
[JsonProperty(PropertyName = Constants.Properties.UniqueKeyPolicy, NullValueHandling = NullValueHandling.Ignore)]
private UniqueKeyPolicy uniqueKeyPolicyInternal;
[JsonProperty(PropertyName = Constants.Properties.ConflictResolutionPolicy, NullValueHandling = NullValueHandling.Ignore)]
private ConflictResolutionPolicy conflictResolutionInternal;
[JsonProperty(PropertyName = "clientEncryptionPolicy", NullValueHandling = NullValueHandling.Ignore)]
private ClientEncryptionPolicy clientEncryptionPolicyInternal;
[JsonProperty(PropertyName = "vectorEmbeddingPolicy", NullValueHandling = NullValueHandling.Ignore)]
private VectorEmbeddingPolicy vectorEmbeddingPolicyInternal;
[JsonProperty(PropertyName = "computedProperties", NullValueHandling = NullValueHandling.Ignore)]
private Collection<ComputedProperty> computedProperties;
/// <summary>
/// This contains additional values for scenarios where the SDK is not aware of new fields.
/// This ensures that if resource is read and updated none of the fields will be lost in the process.
/// </summary>
[JsonExtensionData]
internal IDictionary<string, JToken> AdditionalProperties { get; private set; }
private IReadOnlyList<IReadOnlyList<string>> partitionKeyPathTokens;
private string id;
/// <summary>
/// Initializes a new instance of the <see cref="ContainerProperties"/> class for the Azure Cosmos DB service.
/// </summary>
public ContainerProperties()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ContainerProperties"/> class for the Azure Cosmos DB service.
/// </summary>
/// <param name="id">The Id of the resource in the Azure Cosmos service.</param>
/// <param name="partitionKeyPath">The path to the partition key. Example: /location</param>
public ContainerProperties(string id, string partitionKeyPath)
{
this.Id = id;
this.PartitionKeyPath = partitionKeyPath;
this.ValidateRequiredProperties();
}
/// <summary>
/// Initializes a new instance of the <see cref="ContainerProperties"/> class for the Azure Cosmos DB service.
/// </summary>
/// <param name="id">The Id of the resource in the Azure Cosmos service.</param>
/// <param name="partitionKeyPaths">The paths of the hierarchical partition keys. Example: ["/tenantId", "/userId"]</param>
public ContainerProperties(string id, IReadOnlyList<string> partitionKeyPaths)
{
this.Id = id;
this.PartitionKeyPaths = partitionKeyPaths;
this.ValidateRequiredProperties();
}
/// <summary>
/// Gets or sets the <see cref="Cosmos.PartitionKeyDefinitionVersion"/>
///
/// The partition key definition version 1 uses a hash function that computes
/// hash based on the first 100 bytes of the partition key. This can cause
/// conflicts for documents with partition keys greater than 100 bytes.
///
/// The partition key definition version 2 uses a hash function that computes
/// hash based on the first 2 KB of the partition key.
/// </summary>
/// <returns>The Partition Key Definition Version of the container</returns>
[JsonIgnore]
public PartitionKeyDefinitionVersion? PartitionKeyDefinitionVersion
{
get => (Cosmos.PartitionKeyDefinitionVersion?)this.PartitionKey?.Version;
set
{
if (this.PartitionKey == null)
{
throw new ArgumentOutOfRangeException($"PartitionKey is not defined for container");
}
this.PartitionKey.Version = (Documents.PartitionKeyDefinitionVersion)value;
}
}
/// <summary>
/// Gets or sets the <see cref="ConflictResolutionPolicy" />
/// </summary>
[JsonIgnore]
public ConflictResolutionPolicy ConflictResolutionPolicy
{
get
{
if (this.conflictResolutionInternal == null)
{
this.conflictResolutionInternal = new ConflictResolutionPolicy();
}
return this.conflictResolutionInternal;
}
set => this.conflictResolutionInternal = value ?? throw new ArgumentNullException($"{nameof(value)}");
}
/// <summary>
/// Gets or sets the Id of the resource in the Azure Cosmos DB service.
/// </summary>
/// <value>The Id associated with the resource.</value>
/// <remarks>
/// <para>
/// Every resource within an Azure Cosmos DB database account needs to have a unique identifier.
/// Unlike <see cref="Documents.Resource.ResourceId"/>, which is set internally, this Id is settable by the user and is not immutable.
/// </para>
/// <para>
/// The following characters are restricted and cannot be used in the Id property:
/// '/', '\\', '?', '#'
/// </para>
/// </remarks>
[JsonProperty(PropertyName = Constants.Properties.Id)]
public string Id
{
get => this.id;
set => this.id = value ?? throw new ArgumentNullException(nameof(this.Id));
}
/// <summary>
/// Gets or sets the <see cref="UniqueKeyPolicy"/> that guarantees uniqueness of documents in container in the Azure Cosmos DB service.
/// </summary>
[JsonIgnore]
public UniqueKeyPolicy UniqueKeyPolicy
{
get
{
if (this.uniqueKeyPolicyInternal == null)
{
this.uniqueKeyPolicyInternal = new UniqueKeyPolicy();
}
return this.uniqueKeyPolicyInternal;
}
set
{
if (value == null)
{
throw new ArgumentNullException($"{nameof(value)}");
}
this.uniqueKeyPolicyInternal = value;
}
}
/// <summary>
/// Gets the entity tag associated with the resource from the Azure Cosmos DB service.
/// </summary>
/// <value>
/// The entity tag associated with the resource.
/// </value>
/// <remarks>
/// ETags are used for concurrency checking when updating resources.
/// </remarks>
[JsonProperty(PropertyName = Constants.Properties.ETag, NullValueHandling = NullValueHandling.Ignore)]
public string ETag { get; private set; }
/// <summary>
/// Gets the last modified time stamp associated with <see cref="ContainerProperties" /> from the Azure Cosmos DB service.
/// </summary>
/// <value>The last modified time stamp associated with the resource.</value>
[JsonProperty(PropertyName = Constants.Properties.LastModified, NullValueHandling = NullValueHandling.Ignore)]
[JsonConverter(typeof(UnixDateTimeConverter))]
public DateTime? LastModified { get; private set; }
/// <summary>
/// Gets or sets the client encryption policy information for storing items in a container from the Azure Cosmos service.
/// </summary>
/// <value>
/// It is an optional property.
/// By default, ClientEncryptionPolicy is set to null meaning the feature is turned off for the container.
/// </value>
/// <remarks>
/// <para>
/// The <see cref="ClientEncryptionPolicy"/> will be applied to all the items in the container as the default policy.
/// </para>
/// </remarks>
[JsonIgnore]
public ClientEncryptionPolicy ClientEncryptionPolicy
{
get => this.clientEncryptionPolicyInternal;
set => this.clientEncryptionPolicyInternal = value;
}
/// <summary>
/// Gets the <see cref="IndexingPolicy"/> associated with the container from the Azure Cosmos DB service.
/// </summary>
/// <value>
/// The indexing policy associated with the container.
/// </value>
[JsonIgnore]
public IndexingPolicy IndexingPolicy
{
get
{
if (this.indexingPolicyInternal == null)
{
this.indexingPolicyInternal = new IndexingPolicy();
}
return this.indexingPolicyInternal;
}
set
{
if (value == null)
{
throw new ArgumentNullException($"{nameof(value)}");
}
this.indexingPolicyInternal = value;
}
}
/// <summary>
/// Gets or sets the vector embedding policy containing paths for embeddings along with path-specific settings for the item
/// used in performing vector search on the items in a collection in the Azure CosmosDB database service.
/// </summary>
/// <value>
/// It is an optional property.
/// By default, VectorEmbeddingPolicy is set to null meaning the feature is turned off for the container.
/// </value>
/// <remarks>
/// <para>
/// The <see cref="Cosmos.VectorEmbeddingPolicy"/> will be applied to all the items in the container as the default policy.
/// </para>
/// </remarks>
[JsonIgnore]
internal VectorEmbeddingPolicy VectorEmbeddingPolicy
{
get => this.vectorEmbeddingPolicyInternal;
set => this.vectorEmbeddingPolicyInternal = value;
}
/// <summary>
/// Gets or sets the collection containing <see cref="ComputedProperty"/> objects in the container.
/// </summary>
/// <value>
/// The collection containing <see cref="ComputedProperty"/> objects associated with the container.
/// </value>
/// <summary>
/// Gets or sets the collection containing <see cref="ComputedProperty"/> objects in the container.
/// </summary>
/// <value>
/// The collection containing <see cref="ComputedProperty"/> objects associated with the container.
/// </value>
[JsonIgnore]
#if PREVIEW
public
#else
internal
#endif
Collection<ComputedProperty> ComputedProperties
{
get
{
if (this.computedProperties == null)
{
this.computedProperties = new Collection<ComputedProperty>();
}
return this.computedProperties;
}
set
{
if (value == null)
{
throw new ArgumentException($"{nameof(value)}");
}
this.computedProperties = value;
}
}
/// <summary>
/// Gets the <see cref="ChangeFeedPolicy"/> associated with the container from the Azure Cosmos DB service.
/// </summary>
/// <value>
/// The change feed policy associated with the container.
/// </value>
[JsonIgnore]
#if PREVIEW
public
#else
internal
#endif
ChangeFeedPolicy ChangeFeedPolicy
{
get
{
if (this.changeFeedPolicyInternal == null)
{
this.changeFeedPolicyInternal = new ChangeFeedPolicy();
}
return this.changeFeedPolicyInternal;
}
set => this.changeFeedPolicyInternal = value;
}
/// <summary>
/// Gets the <see cref="GeospatialConfig"/> associated with the collection from the Azure Cosmos DB service.
/// </summary>
/// <value>
/// Geospatial type of collection i.e. geography or geometry
/// </value>
[JsonIgnore]
public GeospatialConfig GeospatialConfig
{
get
{
if (this.geospatialConfigInternal == null)
{
this.geospatialConfigInternal = new GeospatialConfig();
}
return this.geospatialConfigInternal;
}
set => this.geospatialConfigInternal = value;
}
/// <summary>
/// JSON path used for containers partitioning
/// </summary>
[JsonIgnore]
public string PartitionKeyPath
{
get
{
if (this.PartitionKey?.Kind == PartitionKind.MultiHash && this.PartitionKey?.Paths.Count > 1)
{
throw new NotImplementedException($"This subpartitioned container has more than 1 partition key path please use `PartitionKeyPaths`");
}
return this.PartitionKey?.Paths != null && this.PartitionKey.Paths.Count > 0 ? this.PartitionKey?.Paths[0] : null;
}
set
{
if (string.IsNullOrEmpty(value))
{
throw new ArgumentNullException(nameof(this.PartitionKeyPath));
}
PartitionKeyDefinitionVersion? currentDefinitionVersion = this.PartitionKeyDefinitionVersion;
this.PartitionKey = new PartitionKeyDefinition
{
Paths = new Collection<string>() { value }
};
if (currentDefinitionVersion.HasValue)
{
this.PartitionKeyDefinitionVersion = currentDefinitionVersion.Value;
}
}
}
/// <summary>
/// List of JSON paths used for containers with hierarchical partition keys
/// </summary>
[JsonIgnore]
public IReadOnlyList<string> PartitionKeyPaths
{
get => this.PartitionKey?.Paths;
set
{
if (value == null)
{
throw new ArgumentNullException(nameof(this.PartitionKeyPaths));
}
Collection<string> paths = new Collection<string>();
foreach (string path in value)
{
paths.Add(path);
}
this.PartitionKey = new PartitionKeyDefinition
{
Paths = paths,
Kind = Documents.PartitionKind.MultiHash,
Version = Documents.PartitionKeyDefinitionVersion.V2
};
}
}
/// <summary>
/// Gets or sets the time to live base time stamp property path.
/// </summary>
/// <value>
/// It is an optional property.
/// This property should be only present when DefaultTimeToLive is set. When this property is present, time to live
/// for a item is decided based on the value of this property in item.
/// By default, TimeToLivePropertyPath is set to null meaning the time to live is based on the _ts property in item.
/// </value>
#if !INTERNAL
[Obsolete]
#endif
[JsonProperty(PropertyName = Constants.Properties.TimeToLivePropertyPath, NullValueHandling = NullValueHandling.Ignore)]
public string TimeToLivePropertyPath { get; set; }
/// <summary>
/// Gets or sets the default time to live in seconds for item in a container from the Azure Cosmos service.
/// </summary>
/// <value>
/// It is an optional property.
///
/// The unit of measurement is seconds. The maximum allowed value is 2147483647.
/// A valid value must be either a nonzero positive integer, '-1' or <c>null</c>.
///
/// By default, DefaultTimeToLive is set to null meaning the time to live is turned off for the container.
/// </value>
/// <remarks>
/// <para>
/// The <see cref="DefaultTimeToLive"/> will be applied to all the items in the container as the default time-to-live policy.
/// The individual item could override the default time-to-live policy by setting its time to live.
/// </para>
/// <para>
/// When the <see cref="DefaultTimeToLive"/> is <c>null</c>, the time-to-live will be turned off for the container.
/// It means all the items will never expire. The individual item's time to live will be disregarded.
/// </para>
/// <para>
/// When the <see cref="DefaultTimeToLive"/> is '-1', the time-to-live will be turned on for the container.
/// By default, all the items will never expire. The individual item could be given a specific time-to-live value by setting its
/// time to live. The item's time to live will be honored, and the expired items
/// will be deleted in background.
/// </para>
/// <para>
/// When the <see cref="DefaultTimeToLive"/> is a nonzero positive integer, the time-to-live will be turned on for the container.
/// And a default time-to-live in seconds will be applied to all the items. A item will be expired after the
/// specified <see cref="DefaultTimeToLive"/> value in seconds since its last write time.
/// </para>
/// </remarks>
/// <example>
/// The example below disables time-to-live on a container.
/// <code language="c#">
/// <![CDATA[
/// container.DefaultTimeToLive = null;
/// ]]>
/// </code>
/// </example>
/// <example>
/// The example below enables time-to-live on a container. By default, all the items never expire.
/// <code language="c#">
/// <![CDATA[
/// container.DefaultTimeToLive = -1;
/// ]]>
/// </code>
/// </example>
/// <example>
/// The example below enables time-to-live on a container. By default, the item will expire after 1000 seconds
/// since its last write time.
/// <code language="c#">
/// <![CDATA[
/// container.DefaultTimeToLive = 1000;
/// ]]>
/// </code>
/// </example>
[JsonProperty(PropertyName = Constants.Properties.DefaultTimeToLive, NullValueHandling = NullValueHandling.Ignore)]
public int? DefaultTimeToLive { get; set; }
/// <summary>
/// Gets or sets the time to live for analytical store in seconds at container scope for the Azure Cosmos service.
///
/// Analytical store when enabled captures all the item changes in the container. AnalyticalStoreTimeToLiveInSeconds
/// defines the time to live for the changes in analytical store.
/// </summary>
/// <value>
/// It is an optional property.
///
/// The unit of measurement is seconds. The maximum allowed value is 2147483647.
/// A valid value must be either a nonzero positive integer, '-1' or <c>null</c>.
///
/// By default, AnalyticalStoreTimeToLiveInSeconds is set to null meaning analytical store is turned-off.
/// </value>
/// <remarks>
/// <para>
/// The <see cref="AnalyticalStoreTimeToLiveInSeconds"/> is applicable to all the item changes in the container.
/// It cannot be overriden or customizable per item.
/// </para>
/// <para>
/// When the <see cref="AnalyticalStoreTimeToLiveInSeconds"/> is <c>null</c> analytical store is turned-off.
/// It means all the item changes in the container are disregarded.
/// </para>
/// <para>
/// When the <see cref="AnalyticalStoreTimeToLiveInSeconds"/> is '-1', all the items changes will be captured
/// by analytical store and will never expire.
/// </para>
/// <para>
/// When the <see cref="AnalyticalStoreTimeToLiveInSeconds"/> is a nonzero positive integer, all the items
/// changes will be captured by analytical store and expired after the specified time to live.
/// </para>
/// </remarks>
/// <example>
/// The example below disables analytical store on a container.
/// <code language="c#">
/// <![CDATA[
/// container.AnalyticalStoreTimeToLiveInSeconds = null;
/// ]]>
/// </code>
/// </example>
/// <example>
/// The example below enables analytical store on container capturing all changes and never expire.
/// <code language="c#">
/// <![CDATA[
/// container.AnalyticalStoreTimeToLiveInSeconds = -1;
/// ]]>
/// </code>
/// </example>
/// <example>
/// The example below enables analytical store on container capturing all changes and expire after 180days.
/// <code language="c#">
/// <![CDATA[
/// container.AnalyticalStoreTimeToLiveInSeconds = (int)TimeSpan.FromDays(6 * 30).TotalSeconds;
/// ]]>
/// </code>
/// </example>
[JsonProperty(PropertyName = Constants.Properties.AnalyticalStorageTimeToLive, NullValueHandling = NullValueHandling.Ignore)]
public int? AnalyticalStoreTimeToLiveInSeconds { get; set; }
/// <summary>
/// Gets the self-link associated with the resource from the Azure Cosmos DB service.
/// </summary>
/// <value>The self-link associated with the resource.</value>
/// <remarks>
/// A self-link is a static addressable Uri for each resource within a database account and follows the Azure Cosmos DB resource model.
/// E.g. a self-link for a document could be dbs/db_resourceid/colls/coll_resourceid/documents/doc_resourceid
/// </remarks>
[JsonProperty(PropertyName = Constants.Properties.SelfLink, NullValueHandling = NullValueHandling.Ignore)]
public string SelfLink { get; private set; }
/// <summary>
/// The function selects the right partition key constant mapping for <see cref="PartitionKey.None"/>
/// </summary>
internal PartitionKeyInternal GetNoneValue()
{
if (this.PartitionKey == null)
{
throw new ArgumentNullException($"{nameof(this.PartitionKey)}");
}
if (this.PartitionKey.Paths.Count == 0 || (this.PartitionKey.IsSystemKey == true))
{
return PartitionKeyInternal.Empty;
}
else
{
return PartitionKeyInternal.Undefined;
}
}
/// <summary>
/// Only collection cache needs this contract. None are expected to use it.
/// </summary>
/// <param name="resourceId">The resource identifier for the container.</param>
/// <returns>An instance of <see cref="ContainerProperties"/>.</returns>
internal static ContainerProperties CreateWithResourceId(string resourceId)
{
if (string.IsNullOrEmpty(resourceId))
{
throw new ArgumentNullException(nameof(resourceId));
}
return new ContainerProperties()
{
ResourceId = resourceId,
};
}
/// <summary>
/// Initializes a new instance of the <see cref="ContainerProperties"/> class for the Azure Cosmos DB service.
/// </summary>
/// <param name="id">The Id of the resource in the Azure Cosmos service.</param>
/// <param name="partitionKeyDefinition">The partition key definition.</param>
internal ContainerProperties(string id, PartitionKeyDefinition partitionKeyDefinition)
{
this.Id = id;
this.PartitionKey = partitionKeyDefinition;
this.ValidateRequiredProperties();
}
/// <summary>
/// Gets or sets <see cref="PartitionKeyDefinition"/> object in the Azure Cosmos DB service.
/// </summary>
/// <value>
/// <see cref="PartitionKeyDefinition"/> object.
/// </value>
[JsonProperty(PropertyName = Constants.Properties.PartitionKey, NullValueHandling = NullValueHandling.Ignore)]
internal PartitionKeyDefinition PartitionKey { get; set; } = new PartitionKeyDefinition();
/// <summary>
/// Gets the Resource Id associated with the resource in the Azure Cosmos DB service.
/// </summary>
/// <value>
/// The Resource Id associated with the resource.
/// </value>
/// <remarks>
/// A Resource Id is the unique, immutable, identifier assigned to each Azure Cosmos DB
/// resource whether that is a database, a container or a document.
/// These resource ids are used when building up SelfLinks, a static addressable Uri for each resource within a database account.
/// </remarks>
[JsonProperty(PropertyName = Constants.Properties.RId, NullValueHandling = NullValueHandling.Ignore)]
internal string ResourceId { get; private set; }
internal bool HasPartitionKey => this.PartitionKey != null;
internal IReadOnlyList<IReadOnlyList<string>> PartitionKeyPathTokens
{
get
{
if (this.partitionKeyPathTokens != null)
{
return this.partitionKeyPathTokens;
}
if (this.PartitionKey == null)
{
throw new ArgumentNullException(nameof(this.PartitionKey));
}
if (this.PartitionKey.Paths.Count > 1 && this.PartitionKey.Kind != Documents.PartitionKind.MultiHash)
{
throw new NotImplementedException("PartitionKey extraction with composite partition keys not supported.");
}
if (this.PartitionKey.Kind != Documents.PartitionKind.MultiHash && this.PartitionKeyPath == null)
{
throw new ArgumentOutOfRangeException($"Container {this.Id} is not partitioned");
}
if (this.PartitionKey.Kind == Documents.PartitionKind.MultiHash && this.PartitionKeyPaths == null)
{
throw new ArgumentOutOfRangeException($"Container {this.Id} is not partitioned");
}
List<IReadOnlyList<string>> partitionKeyPathTokensList = new List<IReadOnlyList<string>>();
foreach (string path in this.PartitionKey?.Paths)
{
string[] splitPaths = path.Split(ContainerProperties.partitionKeyTokenDelimeter, StringSplitOptions.RemoveEmptyEntries);
partitionKeyPathTokensList.Add(new List<string>(splitPaths));
}
this.partitionKeyPathTokens = partitionKeyPathTokensList;
return this.partitionKeyPathTokens;
}
}
/// <summary>
/// Throws an exception if an invalid id or partition key is set.
/// </summary>
internal void ValidateRequiredProperties()
{
if (this.Id == null)
{
throw new ArgumentNullException(nameof(this.Id));
}
if (this.PartitionKey == null || this.PartitionKey.Paths.Count == 0)
{
throw new ArgumentNullException(nameof(this.PartitionKey));
}
// HACK: Till service can handle the defaults (self-mutation)
// If indexing mode is not 'none' and not paths are set, set them to the defaults
if (this.indexingPolicyInternal != null
&& this.indexingPolicyInternal.IndexingMode != IndexingMode.None
&& this.indexingPolicyInternal.IncludedPaths.Count == 0
&& this.indexingPolicyInternal.ExcludedPaths.Count == 0)
{
this.indexingPolicyInternal.IncludedPaths.Add(new IncludedPath() { Path = IndexingPolicy.DefaultPath });
}
if (this.ClientEncryptionPolicy != null)
{
this.ClientEncryptionPolicy.ValidatePartitionKeyPathsIfEncrypted(this.PartitionKeyPathTokens);
}
}
}
}