From 967bf6f71b82a6eb731e08039ad7b73b97970465 Mon Sep 17 00:00:00 2001 From: Daniel Scott-Raynsford Date: Sun, 31 May 2020 15:33:55 +1200 Subject: [PATCH] Added Get-CosmosDbDocumentJson function --- CHANGELOG.md | 11 + Resolve-Dependency.ps1 | 12 +- STYLEGUIDELINES.md | 58 +-- build.ps1 | 2 +- docs/CosmosDB.md | 10 +- docs/Get-CosmosDbDocument.md | 6 +- docs/Get-CosmosDbDocumentJson.md | 406 ++++++++++++++++++ .../Private/utils/Invoke-CosmosDbRequest.ps1 | 5 +- .../attachments/Get-CosmosDbAttachment.ps1 | 2 +- .../collections/Get-CosmosDbCollection.ps1 | 2 +- .../Public/documents/Get-CosmosDbDocument.ps1 | 142 +----- .../documents/Get-CosmosDbDocumentJson.ps1 | 233 ++++++++++ source/Public/offers/Get-CosmosDbOffer.ps1 | 2 +- tests/TestHelper/TestHelper.psm1 | 6 +- tests/Unit/CosmosDB.documents.Tests.ps1 | 154 +++++++ 15 files changed, 868 insertions(+), 183 deletions(-) create mode 100644 docs/Get-CosmosDbDocumentJson.md create mode 100644 source/Public/documents/Get-CosmosDbDocumentJson.ps1 diff --git a/CHANGELOG.md b/CHANGELOG.md index cff4f65c..66fb6f1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Added `Get-CosmosDbDocumentJson` function - Fixes [Issue #370](https://github.com/PlagueHO/CosmosDB/issues/370). + ### Changed - Changed build jobs `Unit_Test_PSCore6_Ubuntu1604` and @@ -17,6 +21,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 `*-CosmosDbCollection` functions - Fixes [Issue #375](https://github.com/PlagueHO/CosmosDB/issues/375). - Added `Name` as an alias for `Id` parameters in `*-CosmosDbDatabase` functions - Fixes [Issue #374](https://github.com/PlagueHO/CosmosDB/issues/374). +- Refactored `Get-CosmosDbDocument` to be a wrapper for + new function `Get-CosmosDbDocumentJson`. + +### Fixed + +- Fixed `Get-CosmosDbDocument` function partition key formatting + when an `Id` parameter is passed. ## [4.1.0] - 2020-05-15 diff --git a/Resolve-Dependency.ps1 b/Resolve-Dependency.ps1 index 4928e624..1a32d07a 100644 --- a/Resolve-Dependency.ps1 +++ b/Resolve-Dependency.ps1 @@ -3,11 +3,11 @@ param ( [Parameter()] - [String] + [System.String] $DependencyFile = 'RequiredModules.psd1', [Parameter()] - [String] + [System.String] # Path for PSDepend to be bootstrapped and save other dependencies. # Can also be CurrentUser or AllUsers if you wish to install the modules in such scope # Default to $PWD.Path/output/modules @@ -24,12 +24,12 @@ param [Parameter()] [ValidateSet('CurrentUser', 'AllUsers')] - [String] + [System.String] # Scope to bootstrap the PackageProvider and PSGet if not available $Scope = 'CurrentUser', [Parameter()] - [String] + [System.String] # Gallery to use when bootstrapping PackageProvider, PSGet and when calling PSDepend (can be overridden in Dependency files) $Gallery = 'PSGallery', @@ -45,7 +45,7 @@ param $AllowOldPowerShellGetModule, [Parameter()] - [String] + [System.String] # Allow you to specify a minimum version fo PSDepend, if you're after specific features. $MinimumPSDependVersion, @@ -77,7 +77,7 @@ try try { $variableValue = $ResolveDependencyDefaults[$ParamName] - if ($variableValue -is [string]) + if ($variableValue -is [System.String]) { $variableValue = $ExecutionContext.InvokeCommand.ExpandString($variableValue) } diff --git a/STYLEGUIDELINES.md b/STYLEGUIDELINES.md index 17d80986..cc2ddf00 100644 --- a/STYLEGUIDELINES.md +++ b/STYLEGUIDELINES.md @@ -1136,12 +1136,12 @@ function New-Event ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - [String] + [System.String] $Message, [Parameter()] [ValidateSet('operational', 'debug', 'analytic')] - [String] + [System.String] $Channel = 'operational' ) # Implementation... @@ -1170,12 +1170,12 @@ function New-Event ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - [String] + [System.String] $Message, [Parameter()] [ValidateSet('operational', 'debug', 'analytic')] - [String] + [System.String] $Channel = 'operational' ) # Implementation @@ -1192,7 +1192,7 @@ Functions with no parameters should still display an empty parameter block. **Bad:** ```powershell -function Write-Text([Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][String]$Text) +function Write-Text([Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][System.String]$Text) { Write-Verbose -Message $Text } @@ -1216,7 +1216,7 @@ function Write-Text ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - [String] + [System.String] $Text ) @@ -1272,7 +1272,7 @@ function Write-Text { param([Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - [String] $Text ) + [System.String] $Text ) Write-Verbose -Message $Text } @@ -1287,12 +1287,12 @@ function Write-Text ( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] - [String] + [System.String] $Text [Parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] - [String] + [System.String] $PrefixText [Boolean] @@ -1330,7 +1330,7 @@ function Write-Text ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - [String] + [System.String] $Text ) @@ -1347,12 +1347,12 @@ function Write-Text ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - [String] + [System.String] $Text [Parameter()] [ValidateNotNullOrEmpty()] - [String] + [System.String] $PrefixText [Parameter()] @@ -1428,10 +1428,10 @@ function New-Event ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - [String] + [System.String] $Message, [ValidateSet('operational', 'debug', 'analytic')] - [String] + [System.String] $Channel = 'operational' ) } @@ -1446,12 +1446,12 @@ function New-Event ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - [String] + [System.String] $Message, [Parameter()] [ValidateSet('operational', 'debug', 'analytic')] - [String] + [System.String] $Channel = 'operational' ) } @@ -1471,7 +1471,7 @@ function Get-TargetResource [CmdletBinding()] param ( - [String] $SourcePath = 'c:\' + [System.String] $SourcePath = 'c:\' ) } ``` @@ -1485,7 +1485,7 @@ function Get-TargetResource param ( [Parameter()] - [String] + [System.String] $SourcePath = 'c:\' ) } @@ -1516,12 +1516,12 @@ function New-Event ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - [String] + [System.String] $Message, [Parameter()] [ValidateSet('operational', 'debug', 'analytic')] - [String] + [System.String] $Channel = 'operational' ) } @@ -1540,10 +1540,10 @@ function New-Event { param ( - [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][String] + [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][System.String] $Message, - [ValidateSet('operational', 'debug', 'analytic')][String] + [ValidateSet('operational', 'debug', 'analytic')][System.String] $Channel = 'operational' ) } @@ -1558,12 +1558,12 @@ function New-Event ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - [String] + [System.String] $Message, [Parameter()] [ValidateSet('operational', 'debug', 'analytic')] - [String] + [System.String] $Channel = 'operational' ) } @@ -1762,10 +1762,10 @@ function Get-Settings { param ( - [String] + [System.String] $Username - [String] + [System.String] $Password ) ... @@ -1819,7 +1819,7 @@ Extra type declarations can clutter the code. **Bad:** ```powershell -[String] $myString = 'My String' +[System.String] $myString = 'My String' ``` **Bad:** @@ -1971,7 +1971,7 @@ function Get-Something param ( [Parameter(Mandatory = $true)] - [String] + [System.String] $Name = 'My Name' ) @@ -1987,7 +1987,7 @@ function Get-Something param ( [Parameter(Mandatory = $true)] - [String] + [System.String] $Name ) diff --git a/build.ps1 b/build.ps1 index a94f13bd..10968341 100644 --- a/build.ps1 +++ b/build.ps1 @@ -11,7 +11,7 @@ param [string[]]$Tasks = '.', [Parameter()] - [String] + [System.String] $CodeCoverageThreshold = '', [Parameter()] diff --git a/docs/CosmosDB.md b/docs/CosmosDB.md index 09d2a0be..bab9a5aa 100644 --- a/docs/CosmosDB.md +++ b/docs/CosmosDB.md @@ -47,6 +47,10 @@ Return the collections in a Cosmos DB database. Return the resource path for a collection object. +### [Get-CosmosDbContinuationToken](Get-CosmosDbContinuationToken.md) + +Return the continuation token from a response header object. + ### [Get-CosmosDbDatabase](Get-CosmosDbDatabase.md) Return the databases in a Cosmos DB account. @@ -57,7 +61,11 @@ Return the resource path for a database object. ### [Get-CosmosDbDocument](Get-CosmosDbDocument.md) -Return the documents for a Cosmos DB database collection. +Return documents from a Cosmos DB database collection. + +### [Get-CosmosDbDocumentJson](Get-CosmosDbDocumentJson.md) + +Return documents from a Cosmos DB database collection as a JSON string. ### [Get-CosmosDbDocumentResourcePath](Get-CosmosDbDocumentResourcePath.md) diff --git a/docs/Get-CosmosDbDocument.md b/docs/Get-CosmosDbDocument.md index b7388822..33ce8e61 100644 --- a/docs/Get-CosmosDbDocument.md +++ b/docs/Get-CosmosDbDocument.md @@ -9,7 +9,7 @@ schema: 2.0.0 ## SYNOPSIS -Return the documents for a Cosmos DB database collection. +Return documents from a Cosmos DB database collection. ## SYNTAX @@ -41,7 +41,7 @@ This cmdlet will return the documents for a specified collection in a Cosmos DB database. If an Id is specified then only the specified documents will be returned. -A maxiumum of 100 document will be returned if an Id is not +A maximum of 100 document will be returned if an Id is not specified. To retrieve more than 100 documents a continuation token will need to be used. @@ -82,7 +82,7 @@ PS C:\> $query = "SELECT * FROM customers c WHERE (c.id = 'user@contoso.com')" PS C:\> Get-CosmosDbDocument -Context $cosmosDbContext -CollectionId 'MyNewCollection' -Query $query ``` -Querying the documents in a collection. +Query the documents in a collection. ### Example 5 diff --git a/docs/Get-CosmosDbDocumentJson.md b/docs/Get-CosmosDbDocumentJson.md new file mode 100644 index 00000000..f5150075 --- /dev/null +++ b/docs/Get-CosmosDbDocumentJson.md @@ -0,0 +1,406 @@ +--- +external help file: CosmosDB-help.xml +Module Name: CosmosDB +online version: +schema: 2.0.0 +--- + +# Get-CosmosDbDocumentJson + +## SYNOPSIS + +Return documents from a Cosmos DB database collection as a JSON string. + +## SYNTAX + +### Context (Default) + +```powershell +Get-CosmosDbDocumentJson -Context [-Key ] [-KeyType ] + [-Database ] -CollectionId [-Id ] + [-PartitionKey ] [-MaxItemCount ] [-ContinuationToken ] + [-ConsistencyLevel ] [-SessionToken ] + [-PartitionKeyRangeId ] [-Query ] [-QueryParameters ] + [-QueryEnableCrossPartition ] [-ResponseHeader ] [] +``` + +### Account + +```powershell +Get-CosmosDbDocumentJson -Account [-Key ] [-KeyType ] + [-Database ] -CollectionId [-Id ] + [-PartitionKey ] [-MaxItemCount ] [-ContinuationToken ] + [-ConsistencyLevel ] [-SessionToken ] + [-PartitionKeyRangeId ] [-Query ] [-QueryParameters ] + [-QueryEnableCrossPartition ] [-ResponseHeader ] [] +``` + +## DESCRIPTION + +This cmdlet will return the documents for a specified collection in a +Cosmos DB database. If an Id is specified then only the specified +documents will be returned. + +A maximum of 100 document will be returned if an Id is not +specified. To retrieve more than 100 documents a continuation +token will need to be used. + +## EXAMPLES + +### Example 1 + +```powershell +PS C:\> Get-CosmosDbDocumentJson -Context $cosmosDbContext -CollectionId 'MyNewCollection' -Id 'ac12345' +``` + +Return a document with a Id 'ac12345' from a collection in the database. + +### Example 2 + +```powershell +PS C:\> $ResponseHeader = $null +PS C:\> $documents = Get-CosmosDbDocumentJson -Context $cosmosDbContext -CollectionId 'MyNewCollection' -MaxItemCount 5 -ResponseHeader ([ref] $ResponseHeader) +PS C:\> $continuationToken = Get-CosmosDbContinuationToken -ResponseHeader $ResponseHeader +``` + +Get the first 5 documents from the collection in the database +storing a continuation token. + +### Example 3 + +```powershell +PS C:\> $documents = Get-CosmosDbDocumentJson -Context $cosmosDbContext -CollectionId 'MyNewCollection' -MaxItemCount 5 -ContinuationToken $continuationToken +``` + +Get the next 5 documents from a collection in the database using the +continuation token found in the headers from the previous example. + +### Example 4 + +```powershell +PS C:\> $query = "SELECT * FROM customers c WHERE (c.id = 'user@contoso.com')" +PS C:\> Get-CosmosDbDocumentJson -Context $cosmosDbContext -CollectionId 'MyNewCollection' -Query $query +``` + +Query the documents in a collection. + +### Example 5 + +```powershell +PS C:\> $query = "SELECT * FROM customers c WHERE (c.id = @id)" +PS C:\> $queryParameters = @( + @{ name = "@id"; value="user@contoso.com"; } +) +PS C:\> Get-CosmosDbDocumentJson -Context $cosmosDbContext -CollectionId 'MyNewCollection' -Query $query -QueryParameters $queryParameters +``` + +Query the documents in a collection using a parameterized query. + +## PARAMETERS + +### -Account + +The account name of the Cosmos DB to access. + +```yaml +Type: String +Parameter Sets: Account +Aliases: + +Required: True +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -CollectionId + +This is the id of the collection to get the documents for. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: True +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -ConsistencyLevel + +This is the consistency level override. +The override must be the same or weaker than the account's +configured consistency level. +Should not be set if Id is set. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: +Accepted values: Strong, Bounded, Session, Eventual + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Context + +This is an object containing the context information of the Cosmos DB database +that will be deleted. It should be created by \`New-CosmosDbContext\`. + +```yaml +Type: Context +Parameter Sets: Context +Aliases: Connection + +Required: True +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -ContinuationToken + +A string token returned for queries and read-feed operations +if there are more results to be read. +Should not be set if Id is set. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Database + +The name of the database to access in the Cosmos DB account. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Id + +This is the id of the document to return. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Key + +The key to be used to access this Cosmos DB. + +```yaml +Type: SecureString +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -KeyType + +The type of key that will be used to access ths Cosmos DB. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: +Accepted values: master, resource + +Required: False +Position: Named +Default value: Master +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -MaxItemCount + +An integer indicating the maximum number of items to be +returned per page. Should not be set if Id is set. + +```yaml +Type: Int32 +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: -1 +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -PartitionKey + +The partition key value(s) for the document to be read. +Must be included if and only if the collection is created +with a partitionKey definition. + +```yaml +Type: String[] +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -PartitionKeyRangeId + +The partition key range Id for reading data. +Should not be set if Id is set. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Query + +A SQL select query to execute to select the documents. +This should not be specified if Id is specified. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -QueryEnableCrossPartition + +If the collection is partitioned, this must be set to True to +allow execution across multiple partitions. +This should only be specified if Query is specified. + +```yaml +Type: Boolean +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: False +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -QueryParameters + +This is an array of key value pairs (Name, Value) that will be +passed into the SQL Query. +This should only be specified if Query is specified. + +```yaml +Type: Hashtable[] +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -ResponseHeader + +This is a reference variable that will be used to return the +hashtable that contains any headers returned by the request. + +```yaml +Type: PSReference +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -SessionToken + +A string token used with session level consistency. +Clients must echo the latest read value of this header during +read requests for session consistency. +Should not be set if Id is set. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### CommonParameters + +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see about_CommonParameters (http://go.microsoft.com/fwlink/?LinkID=113216). + +## INPUTS + +## OUTPUTS + +### System.Object + +## NOTES + +## RELATED LINKS diff --git a/source/Private/utils/Invoke-CosmosDbRequest.ps1 b/source/Private/utils/Invoke-CosmosDbRequest.ps1 index 9df4c82e..a70a4464 100644 --- a/source/Private/utils/Invoke-CosmosDbRequest.ps1 +++ b/source/Private/utils/Invoke-CosmosDbRequest.ps1 @@ -83,7 +83,7 @@ function Invoke-CosmosDbRequest 'dbs' { # Request for a database object (not containined in a database) - if ([String]::IsNullOrEmpty($ResourcePath)) + if ([System.String]::IsNullOrEmpty($ResourcePath)) { $ResourceLink = 'dbs' } @@ -97,7 +97,7 @@ function Invoke-CosmosDbRequest 'offers' { # Request for an offer object (not contained in a database) - if ([String]::IsNullOrEmpty($ResourcePath)) + if ([System.String]::IsNullOrEmpty($ResourcePath)) { $ResourceLink = 'offers' } @@ -301,6 +301,7 @@ function Invoke-CosmosDbRequest # Display the Request Charge as a verbose message $requestCharge = [Uri]::UnescapeDataString($requestResult.Headers.'x-ms-request-charge').Trim() + if ($requestCharge) { Write-Verbose -Message $($LocalizedData.RequestChargeResults -f $method, $uri, $requestCharge) diff --git a/source/Public/attachments/Get-CosmosDbAttachment.ps1 b/source/Public/attachments/Get-CosmosDbAttachment.ps1 index 90b702de..6df9d905 100644 --- a/source/Public/attachments/Get-CosmosDbAttachment.ps1 +++ b/source/Public/attachments/Get-CosmosDbAttachment.ps1 @@ -67,7 +67,7 @@ function Get-CosmosDbAttachment $resourcePath = ('colls/{0}/docs/{1}/attachments' -f $CollectionId, $DocumentId) - if (-not [String]::IsNullOrEmpty($Id)) + if (-not [System.String]::IsNullOrEmpty($Id)) { $null = $PSBoundParameters.Remove('Id') diff --git a/source/Public/collections/Get-CosmosDbCollection.ps1 b/source/Public/collections/Get-CosmosDbCollection.ps1 index 753ef29f..fef1d3ab 100644 --- a/source/Public/collections/Get-CosmosDbCollection.ps1 +++ b/source/Public/collections/Get-CosmosDbCollection.ps1 @@ -78,7 +78,7 @@ function Get-CosmosDbCollection 'x-ms-max-item-count' = $MaxItemCount } - if (-not [String]::IsNullOrEmpty($ContinuationToken)) + if (-not [System.String]::IsNullOrEmpty($ContinuationToken)) { $headers += @{ 'x-ms-continuation' = $ContinuationToken diff --git a/source/Public/documents/Get-CosmosDbDocument.ps1 b/source/Public/documents/Get-CosmosDbDocument.ps1 index 2e9a1a43..2d60d320 100644 --- a/source/Public/documents/Get-CosmosDbDocument.ps1 +++ b/source/Public/documents/Get-CosmosDbDocument.ps1 @@ -92,146 +92,18 @@ function Get-CosmosDbDocument $ResponseHeader ) - $null = $PSBoundParameters.Remove('Id') - $null = $PSBoundParameters.Remove('CollectionId') - $null = $PSBoundParameters.Remove('MaxItemCount') - $null = $PSBoundParameters.Remove('ContinuationToken') - $null = $PSBoundParameters.Remove('ConsistencyLevel') - $null = $PSBoundParameters.Remove('SessionToken') - $null = $PSBoundParameters.Remove('PartitionKeyRangeId') - $null = $PSBoundParameters.Remove('Query') - $null = $PSBoundParameters.Remove('QueryParameters') - $null = $PSBoundParameters.Remove('QueryEnableCrossPartition') - - if ($PSBoundParameters.ContainsKey('ResponseHeader')) - { - $ResponseHeaderPassed = $true - $null = $PSBoundParameters.Remove('ResponseHeader') - } + $documentJson = Get-CosmosDbDocumentJson @PSBoundParameters - $resourcePath = ('colls/{0}/docs' -f $CollectionId) - $method = 'Get' - $headers = @{} + Write-Verbose -Message ($documentJson | Out-String) -Verbose + $documents = ConvertFrom-Json -InputObject $documentJson - if (-not [String]::IsNullOrEmpty($Id)) - { - # A document Id has been specified - if ($PSBoundParameters.ContainsKey('PartitionKey')) - { - $headers += @{ - 'x-ms-documentdb-partitionkey' = '["' + ($PartitionKey -join '","') + '"]' - } - $null = $PSBoundParameters.Remove('PartitionKey') - } - - $result = Invoke-CosmosDbRequest @PSBoundParameters ` - -Method $method ` - -Headers $headers ` - -ResourceType 'docs' ` - -ResourcePath ('{0}/{1}' -f $resourcePath, $Id) - - $content = Repair-CosmosDbDocumentEncoding -Content $result.Content - $document = ConvertFrom-JSON -InputObject $content - } - else + if ([System.String]::IsNullOrEmpty($Id)) { - $body = '' - - if (-not [String]::IsNullOrEmpty($Query)) - { - # A query has been specified - $method = 'Post' - - $headers += @{ - 'x-ms-documentdb-isquery' = $True - } - - if ($QueryEnableCrossPartition -eq $True) - { - $headers += @{ - 'x-ms-documentdb-query-enablecrosspartition' = $True - } - } - - # Set the content type to application/query+json for querying - $null = $PSBoundParameters.Add('ContentType', 'application/query+json') - - # Create the body JSON for the query - $bodyObject = @{ query = $Query } - if (-not [String]::IsNullOrEmpty($QueryParameters)) - { - $bodyObject += @{ parameters = $QueryParameters } - } - $body = ConvertTo-Json -InputObject $bodyObject - } - else - { - if (-not [String]::IsNullOrEmpty($PartitionKeyRangeId)) - { - $headers += @{ - 'x-ms-documentdb-partitionkeyrangeid' = $PartitionKeyRangeId - } - } - } - - # The following headers apply when querying documents or just getting a list - if ($PSBoundParameters.ContainsKey('PartitionKey')) - { - $headers += @{ - 'x-ms-documentdb-partitionkey' = Format-CosmosDbDocumentPartitionKey -PartitionKey $PartitionKey - } - $null = $PSBoundParameters.Remove('PartitionKey') - } - - $headers += @{ - 'x-ms-max-item-count' = $MaxItemCount - } - - if (-not [String]::IsNullOrEmpty($ContinuationToken)) - { - $headers += @{ - 'x-ms-continuation' = $ContinuationToken - } - } - - if (-not [String]::IsNullOrEmpty($ConsistencyLevel)) - { - $headers += @{ - 'x-ms-consistency-level' = $ConsistencyLevel - } - } - - if (-not [String]::IsNullOrEmpty($SessionToken)) - { - $headers += @{ - 'x-ms-session-token' = $SessionToken - } - } - - <# - Because the headers of this request will contain important information - then we need to use a plain web request. - #> - $result = Invoke-CosmosDbRequest @PSBoundParameters ` - -Method $method ` - -ResourceType 'docs' ` - -ResourcePath $resourcePath ` - -Headers $headers ` - -Body $body - - $content = Repair-CosmosDbDocumentEncoding -Content $result.Content - $body = ConvertFrom-JSON -InputObject $content - $document = $body.Documents - - if ($ResponseHeaderPassed) - { - # Return the result headers - $ResponseHeader.value = $result.Headers - } + $documents = $documents.Documents } - if ($document) + if ($documents) { - return (Set-CosmosDbDocumentType -Document $document) + return (Set-CosmosDbDocumentType -Document $documents) } } diff --git a/source/Public/documents/Get-CosmosDbDocumentJson.ps1 b/source/Public/documents/Get-CosmosDbDocumentJson.ps1 new file mode 100644 index 00000000..c117af20 --- /dev/null +++ b/source/Public/documents/Get-CosmosDbDocumentJson.ps1 @@ -0,0 +1,233 @@ +function Get-CosmosDbDocumentJson +{ + + [CmdletBinding(DefaultParameterSetName = 'Context')] + [OutputType([Object])] + param + ( + [Alias('Connection')] + [Parameter(Mandatory = $true, ParameterSetName = 'Context')] + [ValidateNotNullOrEmpty()] + [CosmosDb.Context] + $Context, + + [Parameter(Mandatory = $true, ParameterSetName = 'Account')] + [ValidateScript({ Assert-CosmosDbAccountNameValid -Name $_ -ArgumentName 'Account' })] + [System.String] + $Account, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [System.Security.SecureString] + $Key, + + [Parameter()] + [ValidateSet('master', 'resource')] + [System.String] + $KeyType = 'master', + + [Parameter()] + [ValidateScript({ Assert-CosmosDbDatabaseIdValid -Id $_ -ArgumentName 'Database' })] + [System.String] + $Database, + + [Parameter(Mandatory = $true)] + [ValidateScript({ Assert-CosmosDbCollectionIdValid -Id $_ -ArgumentName 'CollectionId' })] + [System.String] + $CollectionId, + + [Parameter()] + [ValidateScript({ Assert-CosmosDbDocumentIdValid -Id $_ })] + [System.String] + $Id, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [System.Object[]] + $PartitionKey, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [System.Int32] + $MaxItemCount = -1, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [System.String] + $ContinuationToken, + + [Parameter()] + [ValidateSet('Strong', 'Bounded', 'Session', 'Eventual')] + [System.String] + $ConsistencyLevel, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [System.String] + $SessionToken, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [System.String] + $PartitionKeyRangeId, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [System.String] + $Query, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [Hashtable[]] + $QueryParameters, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [System.Boolean] + $QueryEnableCrossPartition = $False, + + [Alias("ResultHeaders")] + [Parameter()] + [ref] + $ResponseHeader + ) + + $null = $PSBoundParameters.Remove('Id') + $null = $PSBoundParameters.Remove('CollectionId') + $null = $PSBoundParameters.Remove('MaxItemCount') + $null = $PSBoundParameters.Remove('ContinuationToken') + $null = $PSBoundParameters.Remove('ConsistencyLevel') + $null = $PSBoundParameters.Remove('SessionToken') + $null = $PSBoundParameters.Remove('PartitionKeyRangeId') + $null = $PSBoundParameters.Remove('Query') + $null = $PSBoundParameters.Remove('QueryParameters') + $null = $PSBoundParameters.Remove('QueryEnableCrossPartition') + + if ($PSBoundParameters.ContainsKey('ResponseHeader')) + { + $ResponseHeaderPassed = $true + $null = $PSBoundParameters.Remove('ResponseHeader') + } + + $resourcePath = ('colls/{0}/docs' -f $CollectionId) + $method = 'Get' + $headers = @{} + + if ([System.String]::IsNullOrEmpty($Id)) + { + $body = '' + + if (-not [System.String]::IsNullOrEmpty($Query)) + { + # A query has been specified + $method = 'Post' + + $headers += @{ + 'x-ms-documentdb-isquery' = $True + } + + if ($QueryEnableCrossPartition -eq $True) + { + $headers += @{ + 'x-ms-documentdb-query-enablecrosspartition' = $True + } + } + + # Set the content type to application/query+json for querying + $null = $PSBoundParameters.Add('ContentType', 'application/query+json') + + # Create the body JSON for the query + $bodyObject = @{ + query = $Query + } + + if (-not [System.String]::IsNullOrEmpty($QueryParameters)) + { + $bodyObject += @{ parameters = $QueryParameters } + } + + $body = ConvertTo-Json -InputObject $bodyObject + } + else + { + if (-not [System.String]::IsNullOrEmpty($PartitionKeyRangeId)) + { + $headers += @{ + 'x-ms-documentdb-partitionkeyrangeid' = $PartitionKeyRangeId + } + } + } + + # The following headers apply when querying documents or just getting a list + if ($PSBoundParameters.ContainsKey('PartitionKey')) + { + $headers += @{ + 'x-ms-documentdb-partitionkey' = Format-CosmosDbDocumentPartitionKey -PartitionKey $PartitionKey + } + $null = $PSBoundParameters.Remove('PartitionKey') + } + + $headers += @{ + 'x-ms-max-item-count' = $MaxItemCount + } + + if (-not [System.String]::IsNullOrEmpty($ContinuationToken)) + { + $headers += @{ + 'x-ms-continuation' = $ContinuationToken + } + } + + if (-not [System.String]::IsNullOrEmpty($ConsistencyLevel)) + { + $headers += @{ + 'x-ms-consistency-level' = $ConsistencyLevel + } + } + + if (-not [System.String]::IsNullOrEmpty($SessionToken)) + { + $headers += @{ + 'x-ms-session-token' = $SessionToken + } + } + + <# + Because the headers of this request will contain important information + then we need to use a plain web request. + #> + $result = Invoke-CosmosDbRequest @PSBoundParameters ` + -Method $method ` + -ResourceType 'docs' ` + -ResourcePath $resourcePath ` + -Headers $headers ` + -Body $body + + if ($ResponseHeaderPassed) + { + # Return the result headers + $ResponseHeader.value = $result.Headers + } + } + else + { + # A document Id has been specified + if ($PSBoundParameters.ContainsKey('PartitionKey')) + { + $headers += @{ + 'x-ms-documentdb-partitionkey' = Format-CosmosDbDocumentPartitionKey -PartitionKey $PartitionKey + } + $null = $PSBoundParameters.Remove('PartitionKey') + } + + $result = Invoke-CosmosDbRequest @PSBoundParameters ` + -Method $method ` + -Headers $headers ` + -ResourceType 'docs' ` + -ResourcePath ('{0}/{1}' -f $resourcePath, $Id) + } + + $documents = Repair-CosmosDbDocumentEncoding -Content $result.Content + + return $documents +} diff --git a/source/Public/offers/Get-CosmosDbOffer.ps1 b/source/Public/offers/Get-CosmosDbOffer.ps1 index 0a44b5c8..b82de096 100644 --- a/source/Public/offers/Get-CosmosDbOffer.ps1 +++ b/source/Public/offers/Get-CosmosDbOffer.ps1 @@ -50,7 +50,7 @@ function Get-CosmosDbOffer } else { - if (-not [String]::IsNullOrEmpty($Query)) + if (-not [System.String]::IsNullOrEmpty($Query)) { $null = $PSBoundParameters.Remove('Query') diff --git a/tests/TestHelper/TestHelper.psm1 b/tests/TestHelper/TestHelper.psm1 index 1d857fc4..8a3eb302 100644 --- a/tests/TestHelper/TestHelper.psm1 +++ b/tests/TestHelper/TestHelper.psm1 @@ -278,12 +278,12 @@ function Get-InvalidArgumentRecord ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - [String] + [System.String] $Message, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - [String] + [System.String] $ArgumentName ) @@ -312,7 +312,7 @@ function Get-InvalidOperationRecord param ( [ValidateNotNullOrEmpty()] - [String] + [System.String] $Message, [ValidateNotNull()] diff --git a/tests/Unit/CosmosDB.documents.Tests.ps1 b/tests/Unit/CosmosDB.documents.Tests.ps1 index 21454ebd..c94cf485 100644 --- a/tests/Unit/CosmosDB.documents.Tests.ps1 +++ b/tests/Unit/CosmosDB.documents.Tests.ps1 @@ -381,6 +381,160 @@ InModuleScope $ProjectName { } } + Describe 'Get-CosmosDbDocumentJson' -Tag 'Unit' { + It 'Should exist' { + { Get-Command -Name Get-CosmosDbDocumentJson -ErrorAction Stop } | Should -Not -Throw + } + + Context 'When called with context parameter and no Id but with header parameters' { + $script:result = $null + $invokeCosmosDbRequest_parameterfilter = { + $Method -eq 'Get' -and ` + $ResourceType -eq 'docs' + } + + Mock ` + -CommandName Invoke-CosmosDbRequest ` + -MockWith { $script:testGetDocumentResultMulti } + + It 'Should not throw exception' { + $getCosmosDbDocumentJsonParameters = @{ + Context = $script:testContext + CollectionId = $script:testCollection + MaxItemCount = 5 + ContinuationToken = 'token' + ConsistencyLevel = 'Strong' + SessionToken = 'session' + PartitionKeyRangeId = 'partition' + Verbose = $true + } + + { $script:result = Get-CosmosDbDocumentJson @getCosmosDbDocumentJsonParameters } | Should -Not -Throw + } + + It 'Should return expected result' { + $script:result | Should -Be $script:testJsonMulti + } + + It 'Should call expected mocks' { + Assert-MockCalled ` + -CommandName Invoke-CosmosDbRequest ` + -ParameterFilter $invokeCosmosDbRequest_parameterfilter ` + -Exactly -Times 1 + } + } + + Context 'When called with context parameter and no Id with headers returned' { + $script:result = $null + $invokeCosmosDbRequest_parameterfilter = { + $Method -eq 'Get' -and ` + $ResourceType -eq 'docs' + } + + Mock ` + -CommandName Invoke-CosmosDbRequest ` + -MockWith { $script:testGetDocumentResultMulti } + + It 'Should not throw exception' { + $script:ResponseHeader = $null + + $getCosmosDbDocumentJsonParameters = @{ + Context = $script:testContext + CollectionId = $script:testCollection + ResponseHeader = [ref] $script:ResponseHeader + Verbose = $true + } + + { $script:result = Get-CosmosDbDocumentJson @getCosmosDbDocumentJsonParameters } | Should -Not -Throw + } + + It 'Should return expected result' { + $script:result | Should -Be $script:testJsonMulti + $script:ResponseHeader.'x-ms-continuation' | Should -Be 'test' + } + + It 'Should call expected mocks' { + Assert-MockCalled ` + -CommandName Invoke-CosmosDbRequest ` + -ParameterFilter $invokeCosmosDbRequest_parameterfilter ` + -Exactly -Times 1 + } + } + + Context 'When called with context parameter and an Id' { + $script:result = $null + $invokeCosmosDbRequest_parameterfilter = { + $Method -eq 'Get' -and ` + $ResourceType -eq 'docs' -and ` + $ResourcePath -eq ('colls/{0}/docs/{1}' -f $script:testCollection, $script:testDocument1) + } + + Mock ` + -CommandName Invoke-CosmosDbRequest ` + -MockWith { $script:testGetDocumentResultSingle } + + It 'Should not throw exception' { + $getCosmosDbDocumentJsonParameters = @{ + Context = $script:testContext + CollectionId = $script:testCollection + Id = $script:testDocument1 + Verbose = $true + } + + { $script:result = Get-CosmosDbDocumentJson @getCosmosDbDocumentJsonParameters } | Should -Not -Throw + } + + It 'Should return expected result' { + $script:result | Should -Be $script:testJsonSingle + } + + It 'Should call expected mocks' { + Assert-MockCalled ` + -CommandName Invoke-CosmosDbRequest ` + -ParameterFilter $invokeCosmosDbRequest_parameterfilter ` + -Exactly -Times 1 + } + } + + Context 'When called with context parameter and an Id and Partition Key' { + $script:result = $null + + $invokeCosmosDbRequest_parameterfilter = { + $Method -eq 'Get' -and ` + $ResourceType -eq 'docs' -and ` + $ResourcePath -eq ('colls/{0}/docs/{1}' -f $script:testCollection, $script:testDocument1) -and ` + $Headers['x-ms-documentdb-partitionkey'] -eq ('["{0}"]' -f $script:testPartitionKey) + } + + Mock ` + -CommandName Invoke-CosmosDbRequest ` + -MockWith { $script:testGetDocumentResultSingle } + + It 'Should not throw exception' { + $getCosmosDbDocumentJsonParameters = @{ + Context = $script:testContext + CollectionId = $script:testCollection + Id = $script:testDocument1 + PartitionKey = $script:testPartitionKey + Verbose = $true + } + + { $script:result = Get-CosmosDbDocumentJson @getCosmosDbDocumentJsonParameters } | Should -Not -Throw + } + + It 'Should return expected result' { + $script:result | Should -Be $script:testJsonSingle + } + + It 'Should call expected mocks' { + Assert-MockCalled ` + -CommandName Invoke-CosmosDbRequest ` + -ParameterFilter $invokeCosmosDbRequest_parameterfilter ` + -Exactly -Times 1 + } + } + } + Describe 'New-CosmosDbDocument' -Tag 'Unit' { It 'Should exist' { { Get-Command -Name New-CosmosDbDocument -ErrorAction Stop } | Should -Not -Throw