PSCouchDB.psm1
# Global preferences [bool] $Global:CouchDBCachePreference = $false [bool] $Global:CouchDBSaveCredentialPreference = $true # Native Powershell CouchDB class class PSCouchDBDocument { <# .SYNOPSIS CouchDB document .DESCRIPTION Class than representing the CouchDB document .EXAMPLE using module PSCouchDB $doc = New-Object PSCouchDBDocument #> # Propetries [string] $_id [ValidatePattern('(^\d+\-\w{32})')] [string] $_rev [hashtable] $_attachments = @{} hidden [hashtable] $doc = @{} # Constructors # No specified _id PSCouchDBDocument () { $this._id = (New-Guid).Guid.Replace('-', $null) $this.doc.Add('_id', $this._id) } # Specified _id PSCouchDBDocument ([string]$_id) { $this._id = $_id $this.doc.Add('_id', $this._id) } # Specified _id and _rev PSCouchDBDocument ([string]$_id, [string]$_rev) { $this._id = $_id $this._rev = $_rev $this.doc.Add('_id', $this._id) $this.doc.Add('_rev', $this._rev) } # Specified _id, _rev and _attachments PSCouchDBDocument ([string]$_id, [string]$_rev, [PSCouchDBAttachment]$attachment) { $this._id = $_id $this._rev = $_rev $this._attachments.Add($attachment.filename, $attachment) $this.doc.Add('_id', $this._id) $this.doc.Add('_rev', $this._rev) $this.doc.Add('_attachments', @{}) $this.doc._attachments.Add($attachment.filename, @{'content_type' = $attachment.content_type; 'data' = $attachment.data }) } PSCouchDBDocument ([string]$_id, [string]$_rev, [string]$attachment) { $this._id = $_id $this._rev = $_rev $attach = New-Object -TypeName PSCouchDBAttachment -ArgumentList $attachment $this._attachments.Add($attach.filename, $attach) $this.doc.Add('_id', $this._id) $this.doc.Add('_rev', $this._rev) $this.doc.Add('_attachments', @{}) $this.doc._attachments.Add($attach.filename, @{'content_type' = $attach.content_type; 'data' = $attach.data }) } # Methods [hashtable] GetDocument () { return $this.doc } SetDocumentId ([string]$id) { $this.doc['_id'] = $id $this._id = $id } SetElement ([string]$key) { # Check key isn't _id if (-not($key -eq "_id")) { $this.doc[$key] = $null } else { Write-Warning -Message "_id must have a value. _id unchanged." } } SetElement ([string]$key, $value) { if ($key -eq "_id") { $this._id = $value } elseif ($key -eq "_rev") { $this._rev = $value } $this.doc[$key] = $value } RemoveElement ([string]$key) { if ($this.doc.ContainsKey($key)) { $this.doc.Remove($key) } else { Write-Error -Message "Document element `"$key`" doesn't exists." } } [string] ToJson () { return $this.doc | ConvertTo-Json -Depth 10 -Compress:$false } [string] ToJson ([int]$depth) { return $this.doc | ConvertTo-Json -Depth $depth -Compress:$false } [string] ToJson ([int]$depth, [bool]$compress) { return $this.doc | ConvertTo-Json -Depth $depth -Compress:$compress } [hashtable] FromJson ([string]$json) { $body = ConvertFrom-Json -InputObject $json $body.psobject.properties | ForEach-Object { # Skip attachments if ($_.Name -eq '_attachments') { return } if ($_.Name -and $_.Value) { $this.SetElement($_.Name, $_.Value) } else { $this.SetElement($_.Name) } } if ($this.doc._id) { $this._id = $this.doc._id } if ($this.doc._rev) { $this._rev = $this.doc._rev } return $this.doc } AddAttachment ([PSCouchDBAttachment]$attachment) { $this._attachments.Add($attachment.filename, $attachment) if (-not($this.doc.ContainsKey('_attachments'))) { $this.doc.Add('_attachments', @{}) } $this.doc._attachments.Add($attachment.filename, @{'content_type' = $attachment.content_type; 'data' = $attachment.data }) } AddAttachment ([string]$attachment) { $attach = New-Object -TypeName PSCouchDBAttachment -ArgumentList $attachment $this._attachments.Add($attach.filename, $attach) if (-not($this.doc.ContainsKey('_attachments'))) { $this.doc.Add('_attachments', @{}) } $this.doc._attachments.Add($attach.filename, @{'content_type' = $attach.content_type; 'data' = $attach.data }) } ReplaceAttachment ([PSCouchDBAttachment]$attachment) { $this.RemoveAttachment($attachment.filename) $this.AddAttachment($attachment) } ReplaceAttachment ([string]$attachment) { $attach = New-Object -TypeName PSCouchDBAttachment -ArgumentList $attachment $this.RemoveAttachment($attach.filename) $this.AddAttachment($attach) } RemoveAttachment ([string]$attachment) { if ($this._attachments.ContainsKey($attachment)) { $this._attachments.Remove($attachment) $this.doc._attachments.Remove($attachment) } } RemoveAllAttachments () { if ($this.doc.ContainsKey('_attachments')) { $this._attachments = @{} if ($this.doc.ContainsKey('_attachments')) { $this.doc.Remove('_attachments') } } } } class PSCouchDBAttachment { <# .SYNOPSIS CouchDB document attachment .DESCRIPTION Class than representing the CouchDB document attachment .EXAMPLE using module PSCouchDB $attachment = New-Object PSCouchDBAttachment -ArgumentList "C:\test.txt" #> # Propetries [string] $filename [string] $content_type hidden $data # Constructors PSCouchDBAttachment ([string] $path) { if (Test-Path -Path $path) { # Get a filename $name = [System.IO.Path]::GetFileNameWithoutExtension($path) $extension = [System.IO.Path]::GetExtension($path) $this.filename = "$name$extension" # Get a content-type $this.content_type = [PSCouchDBAttachment]::ConfirmMime($this.filename) # Get data if ((Get-Item -Path $path).length -gt 0) { $bytes = [System.Text.Encoding]::UTF8.GetBytes((Get-Content -Path $path)) $this.data = [System.Convert]::ToBase64String($bytes) } else { throw [System.IO.InvalidDataException] "$path attachment is empty." } } else { throw [System.IO.FileNotFoundException] "$path attachment not found." } } [string] GetData () { # Get data to string $bytes = [System.Convert]::FromBase64String($this.data) return [System.Text.Encoding]::UTF8.GetString($bytes) } SaveData ($file) { $this.GetData() | Out-File -FilePath $file -Encoding utf8 } [byte[]] GetRawData () { return [System.Convert]::FromBase64String($this.data) } [string] static ConfirmMime ([string]$filename) { $extension = [System.IO.Path]::GetExtension($filename) $mime = switch ($extension) { # application MIME ".exe" { "application/octet-stream"; break } ".bin" { "application/octet-stream"; break } ".pdf" { "application/pdf"; break } ".crt" { "application/pkcs8"; break } ".cer" { "application/pkcs8"; break } ".p7b" { "application/pkcs8"; break } ".pfx" { "application/pkcs8"; break } ".zip" { "application/zip"; break } ".7z" { "application/zip"; break } ".rar" { "application/zip"; break } ".tar" { "application/zip"; break } ".tar.gz" { "application/zip"; break } # audio MIME ".mp3" { "audio/mpeg"; break } ".mp4" { "audio/mpeg"; break } ".ogg" { "audio/vorbis"; break } ".vob" { "audio/vorbis"; break } # font MIME ".woff" { "font/woff"; break } ".ttf" { "font/ttf"; break } ".otf" { "font/otf"; break } # image MIME ".jpeg" { "image/jpeg"; break } ".jpg" { "image/jpeg"; break } ".png" { "image/png"; break } ".bmp" { "image/bmp"; break } ".svg" { "image/svg+xml"; break } ".heic" { "image/heic"; break } ".tiff" { "image/tiff"; break } ".wmf" { "image/wmf"; break } ".gif" { "image/gif"; break } ".webp" { "image/webp"; break } # model 3d MIME ".3mf" { "model/3mf"; break } ".vml" { "model/vml"; break } ".dwf" { "model/vnd.dwf"; break } # text MIME ".css" { "text/css"; break } ".csv" { "text/csv"; break } ".dns" { "text/dns"; break } ".html" { "text/html"; break } ".md" { "text/markdown"; break } ".rtf" { "text/rtf"; break } ".vcard" { "text/vcard"; break } ".xml" { "text/xml"; break } # video MIME ".3gpp" { "video/3gpp"; break } ".mpeg" { "video/mpeg4-generic"; break } ".avi" { "video/mpeg4-generic"; break } ".xvid" { "video/mpeg4-generic"; break } ".dvix" { "video/mpeg4-generic"; break } ".mpg" { "video/mpeg4-generic"; break } default { "multipart/form-data"; break } } return $mime } } class PSCouchDBQuery { <# .SYNOPSIS Native query of CouchDB .DESCRIPTION Class than representing the native query of CouchDB .EXAMPLE using module PSCouchDB $query = New-Object PSCouchDBQuery #> # Properties of query [hashtable]$selector = @{ } [int]$limit [int]$skip [array]$sort = @() [array]$fields = @() [array]$use_index = @() [int]$r [string]$bookmark [bool]$update = $true [bool]$stable [string]$stale [bool]$execution_stats # Hidden properties hidden [int]$Depth hidden [ValidateSet('$and', '$or', '$not', '$nor', '$all', '$elemMatch', '$allMatch')] [string]$LogicalOperator hidden [ValidateSet('$lt', '$lte', '$eq', '$ne', '$gte', '$gt', '$exists', '$type', '$in', '$nin', '$size', '$mod', '$regex')] [string]$operator # Method for add selector key=value AddSelector ($key, $value) { if (-not($this.selector.ContainsKey($key))) { $this.selector.Add($key, $value) } else { throw "selector $key already exists!" } } # Method for replace selector key=value ReplaceSelector ($key, $value) { if (-not($this.selector.ContainsKey($key))) { $this.selector.Add($key, $value) } else { $this.RemoveSelector($key) $this.selector.Add($key, $value) } } # Method for remove specific selector RemoveSelector ($key) { if ($this.selector.ContainsKey($key)) { $this.selector.Remove($key) } else { throw "selector $key not exists!" } $this.selector } # Method for setting limit properties SetLimit ($limit) { $this.limit = $limit } # Method for setting skip properties SetSkip ($skip) { $this.skip = $skip } # Method for adding sort properties to sort array AddSortAsc ($selector) { foreach ($condition in $this.sort) { if ($condition.Values -contains 'desc') { throw 'Sort "desc" id defined! Remove it before add "asc"' } } $this.sort += @{ $selector = 'asc' } } AddSortDesc ($selector) { foreach ($condition in $this.sort) { if ($condition.Values -contains 'asc') { throw 'Sort "asc" id defined! Remove it before add "desc"' } } $this.sort += @{ $selector = 'desc' } } # Method for removing all sort properties RemoveSort () { $this.sort = @() } # Method for removing one sort properties RemoveSort ($sort) { $newsort = $this.sort | Where-Object { $_.Keys.Where( { $_ -ne $sort }) } $this.sort = $newsort } # Method for adding field properties to fields array AddFields ($fields) { $this.fields += $fields } # Method for adding index properties to indexies array AddIndexies ($indexies) { $this.use_index += $indexies } # Method for removing fields properties to fields array RemoveFields () { $this.fields = @() } # Method for removing one field properties to fields array RemoveFields ($field) { $newfields = $this.fields | Where-Object { $_ -ne $field } $this.fields = $newfields } # Method for remove indexies properties to indexies array RemoveIndexies () { $this.use_index = @() } # Method for remove one index properties to indexies array RemoveIndexies ($index) { $newindex = $this.use_index | Where-Object { $_ -ne $index } $this.use_index = $newindex } # Method for setting read quorum SetReadQuorum ($r) { $this.r = $r } # Method for setting bookmark SetBookmark ($bookmark) { $this.bookmark = $bookmark } # Method for disabling update DisableUpdate () { $this.update = $false } # Method for setting update SetStable ($bool) { $this.stable = $bool } # Method for setting stale SetStale () { $this.DisableUpdate() $this.stable = $true $this.stale = 'ok' } # Method for setting update SetExecutionStat ($bool) { $this.execution_stats = $bool } # Method for adding logical operator AddLogicalOperator ($operator) { if ($this.selector.Count -ne 0) { $this.LogicalOperator = $operator $clone_selector = $this.selector.Clone() $this.selector.Clear() # Check if array or selector if (('$and', '$or', '$nor', '$all') -contains $operator ) { # Array $this.selector.Add($operator, @()) foreach ($selector in $clone_selector.Keys) { $this.selector."$operator" += @{ $selector = $clone_selector[$selector] } } $this.Depth = $this.Depth + 2 } else { # Selector $this.selector.Add($operator, $clone_selector) $this.Depth = $this.Depth + 1 } } else { throw "One or more selector are required!" } } # Method for adding operator to selector AddSelectorOperator ($operator) { if ($this.selector.Count -ne 0) { $this.operator = $operator $clone_selector = $this.selector.Clone() $this.selector.Clear() # Check if array, selector or json if (('$lt', '$lte', '$eq', '$ne', '$gte', '$gt', '$exists', '$type', '$mod', '$regex') -contains $operator) { # JSON foreach ($selector in $clone_selector.Keys) { if (('$and', '$or', '$not', '$nor', '$all', '$elemMatch', '$allMatch') -contains $selector) { $this.selector.Add($selector, $clone_selector[$selector]) continue } $this.selector.Add($selector, @{ }) if ($clone_selector[$selector] -is [int]) { $this.selector.$selector.Add($operator, [int]$clone_selector[$selector]) } elseif (($clone_selector[$selector] -eq "true") -or ($clone_selector[$selector] -eq "false")) { $this.selector.$selector.Add($operator, [bool]$clone_selector[$selector]) } else { $this.selector.$selector.Add($operator, $clone_selector[$selector]) } } } elseif (('$in', '$nin', '$size') -contains $operator) { # Array foreach ($selector in $clone_selector.Keys) { if (('$and', '$or', '$not', '$nor', '$all', '$elemMatch', '$allMatch') -contains $selector) { $this.selector.Add($selector, $clone_selector[$selector]) continue } $this.selector.Add($selector, @{ }) if ($clone_selector[$selector] -is [int]) { $this.selector.$selector.Add($operator, @([int]$clone_selector[$selector])) } elseif (($clone_selector[$selector] -eq "true") -or ($clone_selector[$selector] -eq "false")) { $this.selector.$selector.Add($operator, @([bool]$clone_selector[$selector])) } else { $this.selector.$selector.Add($operator, @($clone_selector[$selector])) } } } $this.Depth = $this.Depth + 3 } else { throw "One or more selector are required!" } } # Method for adding operator to selector and value AddSelectorOperator ($operator, $key, $value) { if ($this.selector.Count -ne 0) { $this.operator = $operator if ($this.selector.ContainsKey($key)) { if (-not(('$and', '$or', '$not', '$nor', '$all', '$elemMatch', '$allMatch') -contains $key)) { # Check if array, selector or json $this.selector.$key = @{ } if (('$lt', '$lte', '$eq', '$ne', '$gte', '$gt', '$exists', '$type', '$mod', '$regex') -contains $operator) { # JSON if ($value -is [int]) { $this.selector.$key.Add($operator, [int]$value) } elseif (($value -eq "true") -or ($value -eq "false")) { $this.selector.$key.Add($operator, [bool]$value) } else { $this.selector.$key.Add($operator, $value) } } elseif (('$in', '$nin', '$size') -contains $operator) { # Array if ($value -is [int]) { $this.selector.$key.Add($operator, @([int]$value)) } elseif (($value -eq "true") -or ($value -eq "false")) { $this.selector.$key.Add($operator, @([bool]$value)) } else { $this.selector.$key.Add($operator, @($value)) } } } $this.Depth = $this.Depth + 3 } else { throw "selector $key not exists!" } } else { throw "One or more selector are required!" } } # Method for get a native query in json format [string] GetNativeQuery () { [hashtable]$query = @{ } if ($this.selector.PSBase.Count -ne 0) { $query.selector = $this.selector $this.Depth = $this.Depth + $query.selector.PSBase.Count } else { throw "One selector is required." } if ($this.limit) { $query.limit = $this.limit } if ($this.skip) { $query.skip = $this.skip } if ($this.sort) { $query.sort = $this.sort } if ($this.fields) { $query.fields = $this.fields } if ($this.use_index) { $query.use_index = $this.use_index } if ($this.r) { $query.r = $this.r } if ($this.bookmark) { $query.bookmark = $this.bookmark } $query.update = $this.update if ($this.stable) { $query.stable = $this.stable } if ($this.stale) { $query.stale = $this.stale } if ($this.execution_stats) { $query.execution_stats = $this.execution_stats } return $query | ConvertTo-Json -Depth ($this.Depth + 1) } } class PSCouchDBView { <# .SYNOPSIS View object for CouchDB design document .DESCRIPTION Class than representing the CouchDB view; this object contains the view function and reduce. .EXAMPLE using module PSCouchDB $design_doc = New-Object PSCouchDBView -ArgumentList "view_name" #> # Properties [PSCustomObject] $view = @{} [string] $name [string] $map [ValidateSet('_approx_count_distinct', '_count', '_stats', '_sum')] [string] $reduce # Constructor PSCouchDBView ([string]$name) { $this.name = $name Add-Member -InputObject $this.view NoteProperty $this.name @{} $this.view."$($this.name)".Add('map', $null) } PSCouchDBView ([string]$name, [string]$map) { $this.name = $name $this.map = $map Add-Member -InputObject $this.view NoteProperty $this.name @{} $this.view."$($this.name)".Add('map', $map) } PSCouchDBView ([string]$name, [string]$map, [string]$reduce) { $this.name = $name $this.map = $map $this.reduce = $reduce Add-Member -InputObject $this.view NoteProperty $this.name @{} $this.view."$($this.name)".Add('map', $map) $this.view."$($this.name)".Add('reduce', $reduce) } # Methods [string] ToString () { return $this.GetJsonView() } [hashtable] GetView () { return $this.view."$($this.name)" } [string] GetJsonView () { return $this.view | ConvertTo-Json } AddMapFunction ([string]$function) { if ($null -eq $this.view."$($this.name)".map) { $this.map = $function $this.view."$($this.name)".map = $function } else { throw "Map function already exists! Use ReplaceMapFunction() for substitute it." } } ReplaceMapFunction ([string]$function) { $this.map = $function $this.view."$($this.name)".map = $function } RemoveMapFunction () { if ($null -ne $this.view."$($this.name)".map) { $this.map = $null $this.view."$($this.name)".map = $null } else { throw "Map function doesn't exists!" } } AddReduceFunction ([string]$function) { if ($null -eq $this.view."$($this.name)".reduce) { $this.reduce = $function $this.view."$($this.name)".reduce = $function } else { throw "Reduce function already exists! Use ReplaceReduceFunction() for substitute it." } } ReplaceReduceFunction ([string]$function) { $this.reduce = $function $this.view."$($this.name)".reduce = $function } RemoveReduceFunction () { if ($null -ne $this.view."$($this.name)".reduce) { $this.reduce = $null $this.view."$($this.name)".reduce = $null } else { throw "Reduce function doesn't exists!" } } static [string] BuildMapFunction ([hashtable] $condition) { <# possible CONDITION: @{ EQUAL = 'doc.field1 == 0'; # Add if condition to function: if (doc.field1 == 0) {} EQUEMIT = 'doc.field1'; # Add emit function to if equal condition: if (doc.field1 == 0) {emit(doc.field1)} MINIMUM = 'doc.field1 < 0'; # Add if condition to function: if (doc.field1 < 0) {} MINEMIT = 'doc.field2'; # Add emit function to if equal condition: if (doc.field1 < 0) {emit(doc.field1)} MAXIMUM = 'doc.field1 > 0'; # Add if condition to function: if (doc.field1 > 0) {} MAXEMIT = 'doc.field3'; # Add emit function to if equal condition: if (doc.field1 > 0) {emit(doc.field1)} EMITDOC = "doc" # If other emit is specified, this is null } #> $fun = "function(doc){{" # Substitute variable in hashtable; the pattern is {NAME} $currentIndex = 0 $replacementList = @() if (-not($condition.ContainsKey('EMITDOC'))) { $condition.Add('EMITDOC', 'doc') } foreach ($key in $condition.Keys) { # Build function switch ($key) { 'EQUAL' { if ($condition.ContainsKey('EQUEMIT')) { $fun += 'if ({EQUAL}) {{emit({EQUEMIT});}}' } else { $fun += 'if ({EQUAL}) {{emit({EMITDOC});}}' } } 'MINIMUM' { if ($condition.ContainsKey('MINEMIT')) { $fun += 'if ({MINIMUM}) {{emit({MINEMIT});}}' } else { $fun += 'if ({MINIMUM}) {{emit({EMITDOC});}}' } } 'MAXIMUM' { if ($condition.ContainsKey('MAXEMIT')) { $fun += 'if ({MAXIMUM}) {{emit({MAXEMIT});}}' } else { $fun += 'if ({MAXIMUM}) {{emit({EMITDOC});}}' } } } $inputPattern = '{(.*)' + $key + '(.*)}' $replacementPattern = '{${1}' + $currentIndex + '${2}}' $fun = $fun -replace $inputPattern, $replacementPattern $replacementList += $condition[$key] $currentIndex++ } $fun += '}}' return $fun -f $replacementList } } class PSCouchDBDesignDoc : PSCouchDBDocument { <# .SYNOPSIS Native CouchDB design document .DESCRIPTION Class than representing the CouchDB design documents, are used to build indexes, validate document updates, format query results, and filter replications. .EXAMPLE using module PSCouchDB $design_doc = New-Object PSCouchDBDesignDoc #> # Properties $views [ValidatePattern("\(\s?newDoc\s?,\s?oldDoc\s?,\s?userCtx\s?,\s?secObj\s?\)")] [string] $validate_doc_update hidden [string] $language = 'javascript' # Constructor PSCouchDBDesignDoc () { $this._id = "_design/$((New-CouchDBUuids -Count 1).uuids[0])" $this.views = New-Object Collections.Generic.List[PSCouchDBView] $this.doc['_id'] = $this._id $this.doc.Add('views', @{}) } # Specified _id PSCouchDBDesignDoc ([string]$_id) { if ($_id -match '_design/') { $this._id = $_id } else { $this._id = "_design/$_id" } $this.views = New-Object Collections.Generic.List[PSCouchDBView] $this.doc['_id'] = $this._id } # Specified _id and _rev PSCouchDBDesignDoc ([string]$_id, [string]$_rev) { if ($_id -match '_design/') { $this._id = $_id } else { $this._id = "_design/$_id" } $this._rev = $_rev $this.views = New-Object Collections.Generic.List[PSCouchDBView] $this.doc['_id'] = $this._id $this.doc['_rev'] = $this._rev } # Specified _id, _rev and _attachments PSCouchDBDesignDoc ([string]$_id, [string]$_rev, [PSCouchDBView]$view) { if ($_id -match '_design/') { $this._id = $_id } else { $this._id = "_design/$_id" } $this._rev = $_rev $this.views = New-Object Collections.Generic.List[PSCouchDBView] $this.views.Add($view) $this.doc['_id'] = $this._id $this.doc['_rev'] = $this._rev $this.doc.Add('views', @{}) $this.doc.views.Add($view.name, $view.GetView()) } # Methods AddView ([PSCouchDBView]$view) { if ($this.views -notcontains $view) { [void] $this.views.Add($view) if (-not($this.doc.ContainsKey('views'))) { $this.doc.Add('views', @{}) } $this.doc.views.Add($view.name, $view.GetView()) } } AddView ([string]$name, [string]$map) { $view = New-Object PSCouchDBView -ArgumentList $name, $map $this.AddView($view) } AddView ([string]$name, [string]$map, [string]$reduce) { $view = New-Object PSCouchDBView -ArgumentList $name, $map, $reduce $this.AddView($view) } RemoveView ([string]$name) { if ($this.views.name -contains $name) { foreach ($view in $this.views) { if ($view.name -eq $name) { [void] $this.views.Remove($view) $this.doc.views.Remove($name) break } } } } ReplaceView ([PSCouchDBView]$view) { $this.RemoveView($view.name) $this.AddView($view) } ReplaceView ([string]$name, [string]$map) { $view = New-Object PSCouchDBView -ArgumentList $name, $map $this.RemoveView($view.name) $this.AddView($view) } ReplaceView ([string]$name, [string]$map, [string]$reduce) { $view = New-Object PSCouchDBView -ArgumentList $name, $map, $reduce $this.RemoveView($view.name) $this.AddView($view) } SetValidateFunction ([string]$function) { $this.validate_doc_update = $function $this.doc.Add("validate_doc_update", $function) } } class PSCouchDBBulkDocument { <# .SYNOPSIS CouchDB bulk document .DESCRIPTION Class than representing the CouchDB bulk document .EXAMPLE using module PSCouchDB $bdocs = New-Object PSCouchDBBulkDocument -ArgumentList '{"_id":"test","name":"test"}' # for multiple docs $doc120 = New-Object PSCouchDBDocument -ArgumentList '120' $doc121 = New-Object PSCouchDBDocument -ArgumentList '121' $doc122 = New-Object PSCouchDBDocument -ArgumentList '122' $bdocs = [PSCouchDBBulkDocument]@{docs=@($doc120,$doc121,$doc122)} #> # Propetries [PSCouchDBDocument[]] $docs # Constructor PSCouchDBBulkDocument () { $this.docs = @() } PSCouchDBBulkDocument ([PSCouchDBDocument] $doc) { $this.docs = @() $this.docs += $doc } PSCouchDBBulkDocument ([string] $doc) { $this.docs = @() $addDoc = New-Object -TypeName PSCouchDBDocument [void] $addDoc.FromJson($doc) $this.docs += $addDoc } PSCouchDBBulkDocument ([PSCouchDBDocument[]] $docs) { $this.docs = $docs } # Method AddDocument ([string] $doc) { $addDoc = New-Object -TypeName PSCouchDBDocument [void] $addDoc.FromJson($doc) $this.docs += $addDoc } AddDocument ([PSCouchDBDocument] $doc) { $this.docs += $doc } RemoveDocument ([string] $_id) { $this.docs = $this.docs | Where-Object { $_._id -ne $_id } } SetDeleted () { foreach ($doc in $this.docs) { $doc.SetElement("_deleted", $true) } } [PSCouchDBDocument[]] GetDocuments () { return $this.docs } [string] ToString () { [hashtable] $documents = @{docs = @() } foreach ($doc in $this.docs) { $documents.docs += $doc.GetDocument() } return $documents | ConvertTo-Json -Depth 99 } } class PSCouchDBSecurity { <# .SYNOPSIS CouchDB security database document .DESCRIPTION Class than representing the CouchDB security database document .EXAMPLE using module PSCouchDB $sec = New-Object PSCouchDBSecurity -ArgumentList 'myadmin' # Multiple names or roles $sec = [PSCouchDBSecurity]@{admins=@{names=@('myadmin','admin'); roles=@('admin')}} $sec = [PSCouchDBSecurity]@{admins=@{names=@('myadmin','admin'); roles=@('admin')}; members=@{names=@('reader','member1'); roles=@('read', 'access')}} #> # Propetries [pscustomobject] $admins = @{ roles = @() names = @() } [pscustomobject] $members = @{ roles = @() names = @() } # Constructor PSCouchDBSecurity () {} PSCouchDBSecurity ([string]$adminName) { $this.admins.names += $adminName } PSCouchDBSecurity ([string]$adminName, [string]$adminRoles) { $this.admins.names += $adminName $this.admins.roles += $adminRoles } PSCouchDBSecurity ([string]$adminName, [string]$adminRole, [string]$memberName) { $this.admins.names += $adminName $this.admins.roles += $adminRole $this.members.names += $memberName } PSCouchDBSecurity ([string]$adminName, [string]$adminRole, [string]$memberName, [string]$memberRole) { $this.admins.names += $adminName $this.admins.roles += $adminRole $this.members.names += $memberName $this.members.roles += $memberRole } PSCouchDBSecurity ([array]$adminsNames, [array]$adminsRoles) { $this.admins.names = $adminsNames $this.admins.roles = $adminsRoles } PSCouchDBSecurity ([array]$adminsNames, [array]$adminsRoles, [array]$membersNames, [array]$membersRoles) { $this.admins.names = $adminsNames $this.admins.roles = $adminsRoles $this.members.names = $membersNames $this.members.roles = $membersRoles } # Method [hashtable] GetAdmins () { return $this.admins } [hashtable] GetMembers () { return $this.members } [string] ToJson () { return $this | ConvertTo-Json } [string] ToString () { return $this.ToJson() } AddAdmins ([string]$name) { $this.admins.names += $name } AddAdmins ([array]$name) { $this.admins.names = $this.admins.names + $name } AddAdmins ([string]$name, [string]$role) { $this.admins.names += $name $this.admins.roles += $role } AddAdmins ([array]$name, [array]$role) { $this.admins.names = $this.admins.names + $name $this.admins.roles = $this.admins.roles + $role } AddMembers ([string]$name) { $this.members.names += $name } AddMembers ([array]$name) { $this.members.names = $this.admins.names + $name } AddMembers ([string]$name, [string]$role) { $this.members.names += $name $this.members.roles += $role } AddMembers ([array]$name, [array]$role) { $this.members.names = $this.members.names + $name $this.members.roles = $this.members.roles + $role } RemoveAdminName ([string]$name) { [array] $this.admins.names = $this.admins.names | Where-Object { $_ -ne $name } } RemoveAdminRole ([string]$role) { [array] $this.admins.roles = $this.admins.roles | Where-Object { $_ -ne $role } } RemoveMemberName ([string]$name) { [array] $this.members.names = $this.members.names | Where-Object { $_ -ne $name } } RemoveMemberRole ([string]$role) { [array] $this.members.roles = $this.members.roles | Where-Object { $_ -ne $role } } } class PSCouchDBReplication { <# .SYNOPSIS CouchDB replication database document .DESCRIPTION Class than representing the CouchDB replication database document .EXAMPLE using module PSCouchDB # local replication $rep = New-Object PSCouchDBReplication -ArgumentList 'db','repdb' # remote replication $rep = New-Object PSCouchDBReplication -ArgumentList 'db','repdb', 'remoteserver' #> # Propetries [string] $_id [ValidatePattern('(^\d+\-\w{32})')] [string] $_rev [System.UriBuilder] $source [System.UriBuilder] $target hidden [bool] $cancel hidden [int] $checkpoint_interval = 0 [bool] $continuous hidden [bool] $create_target hidden [array] $doc_ids = @() [ValidatePattern('(^\w+\/\w+)')] hidden [string] $filter hidden [string] $source_proxy hidden [string] $target_proxy hidden [hashtable] $query_params hidden [string] $selector hidden [string] $since_seq hidden [bool] $use_checkpoints hidden [hashtable] $replicator = @{} # Constuctor PSCouchDBReplication ([string]$sourceDb, [string]$targetDb) { $this._id = "${sourceDb}_${targetDb}" $this.source = "http://localhost:5984/$sourceDb" $this.target = "http://localhost:5984/$targetDb" $this.replicator.Add('_id', $this._id) $this.replicator.Add('source', [uri] $this.source.Uri) $this.replicator.Add('target', [uri] $this.target.Uri) } PSCouchDBReplication ([string]$sourceDb, [string]$targetDb, [string]$targetServer) { $this._id = "${sourceDb}_${targetDb}" $this.source = "http://localhost:5984/$sourceDb" $this.target = "http://${targetServer}:5984/$targetDb" $this.replicator.Add('_id', $this._id) $this.replicator.Add('source', [uri] $this.source.Uri) $this.replicator.Add('target', [uri] $this.target.Uri) } # Method SetRevision ([string]$revision) { $this._rev = $revision $this.replicator.Add('_rev', $this._rev) } AddSourceAuthentication ([string]$user, [string]$passwd) { $this.source.UserName = "${user}:${passwd}" $this.replicator['source'] = [uri] $this.source.Uri } AddTargetAuthentication ([string]$user, [string]$passwd) { $this.target.UserName = "${user}:${passwd}" $this.replicator['target'] = [uri] $this.target.Uri } SetSourceSsl () { $this.source.Scheme = "https" $this.source.Port = 6984 $this.replicator['source'] = [uri] $this.source.Uri } SetSourceSsl ([int]$port) { $this.source.Scheme = "https" $this.source.Port = $port $this.replicator['source'] = [uri] $this.source.Uri } SetTargetSsl () { $this.target.Scheme = "https" $this.target.Port = 6984 $this.replicator['target'] = [uri] $this.target.Uri } SetTargetSsl ([int]$port) { $this.target.Scheme = "https" $this.target.Port = $port $this.replicator['target'] = [uri] $this.target.Uri } SetSourceServer ([string]$server) { $this.source.Host = $server $this.replicator['source'] = [uri] $this.source.Uri } SetTargetServer ([string]$server) { $this.target.Host = $server $this.replicator['target'] = [uri] $this.target.Uri } SetCancel () { $this.cancel = $true $this.replicator.Add('cancel', $this.cancel) } SetCheckpointInterval ([int]$ms) { $this.checkpoint_interval = $ms $this.replicator.Add('checkpoint_interval', $this.checkpoint_interval) } SetContinuous () { $this.continuous = $true $this.replicator.Add('continuous', $this.continuous) } CreateTarget () { $this.create_target = $true $this.replicator.Add('create_target', $this.create_target) } AddDocIds ([array]$ids) { $this.doc_ids += $this.doc_ids + $ids $this.replicator.Add('doc_ids', $this.doc_ids) } SetFilter ([string]$filter) { $this.filter = $filter $this.replicator.Add('filter', $this.filter) } SetSourceProxy ([string]$proxyUri) { $this.source_proxy = $proxyUri $this.replicator.Add('source_proxy', [uri] $this.source_proxy) } SetTargetProxy ([string]$proxyUri) { $this.target_proxy = $proxyUri $this.replicator.Add('target_proxy', [uri] $this.target_proxy) } SetQueryParams ([hashtable]$paramaters) { $this.query_params = $paramaters $this.replicator.Add('query_params', $this.query_params) } SetSelector ([string]$selector) { $this.selector = $selector $this.replicator.Add('selector', $this.selector) } SetSelector ([PSCouchDBQuery]$selector) { $this.selector = $selector.GetNativeQuery() $this.replicator.Add('selector', $this.selector) } SetSinceSequence ([string]$sequence) { $this.since_seq = $sequence $this.replicator.Add('since_seq', $this.since_seq) } UseCheckpoints () { $this.use_checkpoints = $true $this.replicator.Add('use_checkpoints', $this.use_checkpoints) } [hashtable] GetDocument () { return $this.replicator } [string] ToJson () { return $this.GetDocument() | ConvertTo-Json -Depth 5 } [string] ToString () { return $this.ToJson() } } class PSCouchDBRequest { <# .SYNOPSIS CouchDB web request .DESCRIPTION Class than representing the CouchDB web request .EXAMPLE using module PSCouchDB # Get database info $req = New-Object PSCouchDBRequest -ArgumentList 'db' # GET http://localhost:5984/db $req.Request() # remote replication $req = New-Object PSCouchDBRequest -ArgumentList 'db','doc' # GET http://localhost:5984/db/doc $req.Request() #> # Propetries [System.UriBuilder] $uri [ValidateSet("HEAD", "GET", "PUT", "DELETE", "POST")] [string] $method = 'GET' [string] $protocol = 'http' [string] $server = 'localhost' [int] $port = 5984 [string] $database [string] $document [PSCouchDBAttachment] $attachment [PSCredential] $authorization [string] $parameter [string] $data hidden [bool] $cache hidden [System.Net.WebRequest] $client hidden [System.Net.WebProxy] $proxy # Constructor PSCouchDBRequest () { # Add uri if ($this.server -match "^http(?s)") { $this.uri = New-Object -TypeName System.UriBuilder -ArgumentList $this.server $this.server = $this.uri.Host $this.protocol = $this.uri.Scheme $this.port = $this.uri.Port $this.parameter = $this.uri.Query } else { $this.uri = New-Object -TypeName System.UriBuilder -ArgumentList $this.protocol, $this.server, $this.port } Add-Member -InputObject $this.uri LastStatusCode 0 } PSCouchDBRequest ([string]$database) { # Add uri if ($this.server -match "^http(?s)") { $this.uri = New-Object -TypeName System.UriBuilder -ArgumentList $this.server $this.server = $this.uri.Host $this.protocol = $this.uri.Scheme $this.port = $this.uri.Port $this.parameter = $this.uri.Query } else { $this.database = $database $this.uri = New-Object -TypeName System.UriBuilder -ArgumentList $this.protocol, $this.server, $this.port, $this.database } Add-Member -InputObject $this.uri LastStatusCode 0 } PSCouchDBRequest ([string]$database, [string]$document) { # Add uri if ($this.server -match "^http(?s)") { $this.uri = New-Object -TypeName System.UriBuilder -ArgumentList $this.server $this.server = $this.uri.Host $this.protocol = $this.uri.Scheme $this.port = $this.uri.Port $this.parameter = $this.uri.Query } else { $this.database = $database $this.document = $document $Path = $this.database, $this.document -join "/" $this.uri = New-Object -TypeName System.UriBuilder -ArgumentList $this.protocol, $this.server, $this.port, $Path } Add-Member -InputObject $this.uri LastStatusCode 0 } # Method [PSCustomObject] Request () { # Create web client $this.client = [System.Net.WebRequest]::Create($this.uri.Uri) $this.client.ContentType = "application/json; charset=utf-8"; $this.client.Method = $this.method $this.client.UserAgent = "User-Agent: PSCouchDB (compatible; MSIE 7.0;)" # Check proxy if ($this.proxy) { $this.client.Proxy = $this.proxy } # Check authorization if ($this.authorization) { $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("$($this.uri.UserName):$($this.uri.Password)"))) $this.client.Headers.Add("Authorization", ("Basic {0}" -f $base64AuthInfo)) } # Check data if ($this.data -or $this.attachment) { $Stream = $this.client.GetRequestStream() if ($this.data) { $Body = [byte[]][char[]]$this.data $Stream.Write($Body, 0, $Body.Length) } # Check attachment elseif ($this.attachment) { $this.client.ContentType = $this.attachment.content_type $Body = [byte[]]$this.attachment.GetRawData() $Stream.Write($Body, 0, $Body.Length) } $Stream.Close() } try { [System.Net.WebResponse] $resp = $this.client.GetResponse() $this.uri.LastStatusCode = $resp.StatusCode } catch [System.Net.WebException] { [System.Net.HttpWebResponse] $errcode = $_.Exception.Response $this.uri.LastStatusCode = $errcode.StatusCode throw ([PSCouchDBRequestException]::New($errcode.StatusCode, $errcode.StatusDescription)).CouchDBMessage } $rs = $resp.GetResponseStream() [System.IO.StreamReader] $sr = New-Object System.IO.StreamReader -ArgumentList $rs [string] $results = $sr.ReadToEnd() $resp.Close() # Check cache if ($this.cache) { $cached = ($results | ConvertFrom-Json) [void]$this.uri.Cache.Add($cached) } if ($results -match "^({.*)|(\[.*)$") { return $results | ConvertFrom-Json } else { return [PSCustomObject]@{ results = $results } } } RequestAsJob ([string]$name) { $job = Start-Job -Name $name { param($uri, $method, $user, $pass, $data, $attachment) # Create web client $Request = [System.Net.WebRequest]::Create($uri) $Request.ContentType = "application/json; charset=utf-8"; $Request.Method = $method $Request.UserAgent = "User-Agent: PSCouchDB (compatible; MSIE 7.0;)" # Check proxy if ($this.proxy) { $this.client.Proxy = $this.proxy } # Check authorization if ($user -and $pass) { $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("${user}:${pass}"))) $Request.Headers.Add("Authorization", ("Basic {0}" -f $base64AuthInfo)) } # Check data if ($data -or $attachment) { $Stream = $Request.GetRequestStream() if ($data) { $Body = [byte[]][char[]]$data $Stream.Write($Body, 0, $Body.Length) } # Check attachment elseif ($attachment) { $Request.ContentType = $ttachment.content_type $Body = [byte[]]$attachment.GetRawData() $Stream.Write($Body, 0, $Body.Length) } $Stream.Close() } try { [System.Net.WebResponse] $resp = $Request.GetResponse() } catch [System.Net.WebException] { [System.Net.HttpWebResponse] $errcode = $_.Exception.Response throw "[$($errcode.StatusCode)] Error.`nCouchDB Response -> $($errcode.StatusDescription)" } $rs = $resp.GetResponseStream() [System.IO.StreamReader] $sr = New-Object System.IO.StreamReader -ArgumentList $rs [string] $results = $sr.ReadToEnd() $resp.Close() if ($results -match "^({.*)|(\[.*)$") { return $results | ConvertFrom-Json } else { return [PSCustomObject]@{ results = $results } } } -ArgumentList $this.uri.Uri, $this.method, $(if ($this.authorization) {$this.authorization.UserName} else {$null}), $(if ($this.authorization) {$this.authorization.GetNetworkCredential().Password} else {$null}), $this.data, $this.attachment Register-TemporaryEvent $job "StateChanged" -Action { Write-Host -ForegroundColor Green "#$($sender.Id) ($($sender.Name)) complete." } } [string] GetHeader () { # Create web client $this.client = [System.Net.WebRequest]::Create($this.uri.Uri) $this.client.ContentType = "application/json; charset=utf-8"; $this.client.Method = 'HEAD' $this.client.UserAgent = "User-Agent: PSCouchDB (compatible; MSIE 7.0;)" # Check proxy if ($this.proxy) { $this.client.Proxy = $this.proxy } # Check authorization if ($this.authorization) { $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("$($this.uri.UserName):$($this.uri.Password)"))) $this.client.Headers.Add("Authorization", ("Basic {0}" -f $base64AuthInfo)) } try { [System.Net.WebResponse] $resp = $this.client.GetResponse() $resp.Close() $this.uri.LastStatusCode = $resp.StatusCode } catch [System.Net.WebException] { [System.Net.HttpWebResponse] $errcode = $_.Exception.Response $this.uri.LastStatusCode = $errcode.StatusCode throw ([PSCouchDBRequestException]::New($errcode.StatusCode, $errcode.StatusDescription)).CouchDBMessage } return $resp.Headers.ToString() } SetProxy ([string]$uri) { $proxyUri = [uri]$uri $this.proxy = New-Object System.Net.WebProxy $this.proxy.Address = $proxyUri $this.proxy.BypassProxyOnLocal = $true } SetProxy ([string]$uri, [string]$user, [string]$pass) { $proxyUri = [uri]$uri $this.proxy = New-Object System.Net.WebProxy $this.proxy.Credentials = [System.Net.NetworkCredential]::new($user, $pass) $this.proxy.Address = $proxyUri $this.proxy.BypassProxyOnLocal = $true } SetProxy ([string]$uri, [PSCredential]$credential) { $auth = $credential.UserName, $credential.GetNetworkCredential().Password $this.SetProxy($uri, $auth[0], $auth[1]) } RemoveProxy () { $this.proxy = $null } SetSsl () { $this.protocol = 'https' $this.uri.Scheme = 'https' $this.SetPort(6984) } SetSsl ([int]$port) { $this.protocol = 'https' $this.uri.Scheme = 'https' $this.SetPort($port) } SetPort ([int]$port) { $this.port = $port $this.uri.Port = $port } SetServer ([string]$server) { if ($server -match "^http(?s)") { $this.server = $server $this.uri = New-Object -TypeName System.UriBuilder -ArgumentList $this.server } else { $srv = $server -split '/',2 $this.server = $srv[0] $this.uri = New-Object -TypeName System.UriBuilder -ArgumentList $this.protocol,$this.server,$this.port,$srv[1] } $this.uri.Scheme = $this.protocol $this.uri.Port = $this.port $this.uri.Query = $this.parameter Add-Member -InputObject $this.uri LastStatusCode 0 } AddAuthorization ([PSCredential]$credential) { $this.authorization = $credential $this.uri.UserName = "$($credential.UserName):$($credential.GetNetworkCredential().Password)" } AddAuthorization ([string]$auth) { # Check if string is in this format: word:word if ($auth -match "^.*\:.*$") { $newAuth = $auth -split ":" [SecureString]$secStringPassword = ConvertTo-SecureString $newAuth[1] -AsPlainText -Force [PSCredential]$credOject = New-Object System.Management.Automation.PSCredential ($newAuth[0], $secStringPassword) $this.AddAuthorization($credOject) } else { throw [System.Text.RegularExpressions.RegexMatchTimeoutException]::New('Authorization string must be this format: "user:password"') } } SetMethod ([string]$method) { $this.method = $method } SetDatabase ([string]$database) { $this.database = $database $path = "{0}" -f $database $this.uri.Path = $path } SetDocument ([string]$document) { if ($this.database) { $this.document = $document $path = "{0}/{1}" -f $this.database, $document $this.uri.Path = $path } else { throw [System.Net.WebException] "Database isn't set." } } SetParameter ([array]$parameter) { if ($this.database) { $this.parameter = $parameter -join '&' $this.uri.Query = $this.parameter } else { throw [System.Net.WebException] "Database isn't set." } } SetData ([string]$json) { $this.data = $json } AddAttachment ([string]$file) { if ($this.document) { $attach = New-Object -TypeName PSCouchDBAttachment -ArgumentList $file $path = "{0}/{1}/{2}" -f $this.database, $this.document, $attach.filename $this.uri.Path = $path $this.attachment = $attach } else { throw [System.Net.WebException] "Document isn't set." } } [string] GetData () { return $this.data } [int] GetStatus () { return $this.uri.LastStatusCode } EnableCache () { $this.cache = $true $c = New-Object System.Collections.ArrayList Add-Member -InputObject $this.uri Cache $c } DisableCache () { $this.cache = $false } ClearCache () { $this.uri.Cache = New-Object System.Collections.ArrayList } [uri] GetUri () { return $this.uri.Uri } [string] ToString () { $stringUri = New-Object -TypeName System.UriBuilder -ArgumentList $this.uri.Uri # Remove Username and Password in string mode for security reason $stringUri.Password = $stringUri.UserName = $null $str = " {0} {1} Host: {2} Param: {3} Uri: {4} {5}" -f $this.method, $this.uri.Path, $this.uri.Host, $this.uri.Query, $stringUri.Uri, $this.data return $str } } # CouchDB exception class class PSCouchDBRequestException : System.Exception { [string] $CouchDBMessage [int] $CouchDBStausCode PSCouchDBRequestException([int]$statusCode, [string]$response) { $this.CouchDBStausCode = $statusCode switch ($this.CouchDBStausCode) { 304 { $this.CouchDBMessage = "[$($this.CouchDBStausCode)] Not Modified: The additional content requested has not been modified." } 400 { $this.CouchDBMessage = "[$($this.CouchDBStausCode)] Bad Request: Bad request structure. The error can indicate an error with the request URL, path or headers." } 401 { $this.CouchDBMessage = "[$($this.CouchDBStausCode)] Unauthorized: The item requested was not available using the supplied authorization, or authorization was not supplied." } 403 { $this.CouchDBMessage = "[$($this.CouchDBStausCode)] Forbidden: The requested item or operation is forbidden." } 404 { $this.CouchDBMessage = "[$($this.CouchDBStausCode)] Not Found: The requested content could not be found." } 405 { $this.CouchDBMessage = "[$($this.CouchDBStausCode)] Method Not Allowed: A request was made using an invalid HTTP request type for the URL requested." } 406 { $this.CouchDBMessage = "[$($this.CouchDBStausCode)] Not Acceptable: The requested content type is not supported by the server." } 409 { $this.CouchDBMessage = "[$($this.CouchDBStausCode)] Conflict: Request resulted in an update conflict." } 412 { $this.CouchDBMessage = "[$($this.CouchDBStausCode)] Precondition Failed: The request headers from the client and the capabilities of the server do not match." } 413 { $this.CouchDBMessage = "[$($this.CouchDBStausCode)] Request Entity Too Large: A document exceeds the configured couchdb/max_document_size value or the entire request exceeds the httpd/max_http_request_size value." } 415 { $this.CouchDBMessage = "[$($this.CouchDBStausCode)] Unsupported Media Type: The content types supported, and the content type of the information being requested or submitted indicate that the content type is not supported." } 416 { $this.CouchDBMessage = "[$($this.CouchDBStausCode)] Requested Range Not Satisfiable: The range specified in the request header cannot be satisfied by the server." } 417 { $this.CouchDBMessage = "[$($this.CouchDBStausCode)] Expectation Failed: The bulk load operation failed." } { $this.CouchDBStausCode -ge 500 } { $this.CouchDBMessage = "[$($this.CouchDBStausCode)] Internal Server Error: The request was invalid, either because the supplied JSON was invalid, or invalid information was supplied as part of the request." } Default { $this.CouchDBMessage = "[$($this.CouchDBStausCode)] Unknown Error: something wrong." } } if ($response) { $this.CouchDBMessage += "`nCouchDB Response -> $response" } } } # Functions of CouchDB module function Send-CouchDBRequest { <# .SYNOPSIS Send a request through rest method to CouchDB server. .DESCRIPTION This command builds the url, data and send to CouchDB server. .PARAMETER Method The REST method. Default is "GET". The avalaible methods are: "HEAD","GET","PUT","DELETE","POST" .PARAMETER Server The CouchDB server name. Default is localhost. This takes part in the url here: http://{server}. .PARAMETER Port The CouchDB server port. Default is 5984. This takes part in the url here: http://localhost:{port}. .PARAMETER Database The CouchDB database. This takes part in the url here: http://localhost:5984/{database}. .PARAMETER Document The CouchDB document. This takes part in the url here: http://localhost:5984/db/{document}. .PARAMETER Authorization The CouchDB authorization form; user and password. Authorization format like this: user:password Can specified PSCredential. This takes part in the url here: http://{authorization}@localhost:5984. .PARAMETER Revision The CouchDB revision document. The revision document format like this: {count}-{uuid} 2-b91bb807b4685080c6a651115ff558f5 This takes part in the url here: http://localhost:5984/db/doc?rev={revision}. .PARAMETER Params The CouchDB other parameter. This takes part in the url here: http://localhost:5984/db/doc?{param} http://localhost:5984/db/doc?{param}={value}. .PARAMETER Attachment The CouchDB document attachment. .PARAMETER Data The CouchDB document data. Is a Json data format. The encoding is UTF-8. .PARAMETER Ssl Set ssl connection on CouchDB server. This modify protocol to https and port to 6984. https://localhost:6984. .PARAMETER JobName JobName for background powershell job. To get a result for a Job, run "Get-Job -Id <number> | Receive-Job -Keep" .PARAMETER ProxyServer Proxy server through which all non-local calls pass. Ex. ... -ProxyServer 'http://myproxy.local:8080' ... .PARAMETER ProxyCredential Proxy server credential. It must be specified with a PSCredential object. .EXAMPLE This example get a database "db": Send-CouchDBRequest -Server couchdb1.local -Method "GET" -Database db .EXAMPLE This example get a document "doc1" on database "db": Send-CouchDBRequest -Server couchdb1.local -Method "GET" -Database db -Document doc1 .EXAMPLE This example get a document "doc1" on database "db" on "localhost" server in SSL connection: Send-CouchDBRequest -Method "GET" -Database db -Document doc1 -Ssl:$true .EXAMPLE This example get a document "doc1" on database "db" on "localhost" server in SSL connection, but use a HTTP uri: Send-CouchDBRequest -Server "http://couchdb1.local/couch" -Method "GET" -Database db -Document doc1 -Ssl:$true .LINK https://pscouchdb.readthedocs.io/en/latest/classes.html#pscouchdbrequest-class #> [CmdletBinding()] param ( [ValidateSet("HEAD", "GET", "PUT", "DELETE", "POST")] [string] $Method, [string] $Server, [int] $Port, [string] $Database, [string] $Document, $Authorization, [string] $Revision, [string] $Attachment, [string] $Data, [array] $Params, [switch] $Ssl, [string] $JobName, [string] $ProxyServer, [pscredential] $ProxyCredential ) # Create PSCouchDBRequest object $req = New-Object PSCouchDBRequest $parameters = @() # Set cache if ($Global:CouchDBCachePreference) { $req.EnableCache() } if ($Server) { Write-Verbose -Message "Set server to $Server" $req.SetServer($Server) } # Set proxy server if ($ProxyServer) { if ($ProxyCredential -is [pscredential]) { Write-Verbose -Message "Set proxy server $ProxyServer with credential" $req.SetProxy($ProxyServer, $ProxyCredential) } else { Write-Verbose -Message "Set proxy server $ProxyServer" $req.SetProxy($ProxyServer) } } # Set protocol if ($Ssl.IsPresent) { # Set default port Write-Verbose -Message "Enable SSL on port 6984" $req.SetSsl() } # Set port if ($Port) { Write-Verbose -Message "Set port on $Port" $req.SetPort($Port) } # Set method switch ($Method) { "HEAD" { $req.SetMethod("HEAD") } "GET" { $req.SetMethod("GET") } "PUT" { $req.SetMethod("PUT") } "DELETE" { $req.SetMethod("DELETE") } "POST" { $req.SetMethod("POST") } Default { $req.SetMethod("GET") } } Write-Verbose -Message "Set method to $($req.method)" # Set database if ($Database) { if ($Database -match "\?") { $arr = $Database -split "\?" $Database = $arr[0] $Param = $arr[1] if ($Param) { $parameters += $Param } } Write-Verbose -Message "Set database to $Database" $req.SetDatabase($Database) } # Set document if ($Document) { if ($Document -match "\?") { $arr = $Document -split "\?" $Document = $arr[0] $Param = $arr[1] if ($Param) { $parameters += $Param } } Write-Verbose -Message "Set document to $Document" $req.SetDocument($Document) } # Set attachment if ($Attachment) { if ('GET','HEAD' -contains $Method) { Write-Verbose -Message "Set attachment to $Attachment" $req.SetDocument("$Document/$Attachment") } else { if (-not(Test-Path -Path $Attachment -ErrorAction SilentlyContinue)) { $req.SetDocument("$Document/$Attachment") } else { Write-Verbose -Message "Set attachment to $Attachment" $req.AddAttachment($Attachment) } } } # Set revision if ($Revision) { Write-Verbose -Message "Set revision to $Revision" $parameters += "rev=$Revision" } # Check other params if ($Params) { $parameters += $Params } if ($parameters) { Write-Verbose -Message "Set parameters: $parameters" $req.SetParameter($parameters) } # Check authorization if ($Authorization -or $Global:CouchDBCredential) { if ($Global:CouchDBSaveCredentialPreference) { if (-not($Global:CouchDBCredential)) { $Global:CouchDBCredential = $Authorization } # Check if authorization has been changed if ($Authorization -and $Global:CouchDBCredential -ne $Authorization) { Write-Verbose -Message "Override global authorization" $Global:CouchDBCredential = $Authorization } Write-Verbose -Message "Add authorization" $req.AddAuthorization($Global:CouchDBCredential) } else { Remove-CouchDBSession Write-Verbose -Message "Add authorization" $req.AddAuthorization($Authorization) } } # Check json data if ($Data) { Write-Verbose -Message "Set json data to: $Data" $req.SetData($Data) } # Get header or request Write-Verbose -Message "Request to CouchDB server: $req" if ($Method -eq "HEAD") { $req.GetHeader() } else { if ($JobName) { $req.RequestAsJob($JobName) } else { $req.Request() # Add to cache if ($req.cache) { if ($CouchDBCache) { [void]$CouchDBCache.AddRange($req.uri.Cache) } else { $Global:CouchDBCache = $req.uri.Cache } } } } } function Search-CouchDBHelp () { <# .SYNOPSIS Search help. .DESCRIPTION Search pattern keyword in a CouchDB help topic. .PARAMETER Pattern The pattern of serach criteria. The pattern it can be a verb, a nuoun or a parameter. .EXAMPLE Search-CouchDBHelp -Pattern "Database" .EXAMPLE Search-CouchDBHelp -Pattern "Get" .LINK https://pscouchdb.readthedocs.io/en/latest/intro.html#start #> [CmdletBinding()] param( [Parameter(mandatory = $true, ValueFromPipeline = $true)] $Pattern ) $helpNames = $(Get-Help *CouchDB* | Where-Object { $_.Category -ne "Alias" }) foreach ($helpTopic in $helpNames) { $content = Get-Help -Full $helpTopic.Name | Out-String if ($content -match "(.{0,30}$Pattern.{0,30})") { $helpTopic | Add-Member NoteProperty Match $matches[0].Trim() $helpTopic | Select-Object Name, Match } } } function New-CouchDBObject () { <# .SYNOPSIS Create a PSCouchDB custom object. .DESCRIPTION Create a PSCouchDB custom object. For example create a document object, design document object, attachment object etc... .PARAMETER TypeName The name of the object than you would create. .PARAMETER ArgumentList The argument of constructor of object. .EXAMPLE New-CouchDBObject -TypeName PSCouchDBDocument -ArgumentList '1-0033838372622627' .EXAMPLE New-CouchDBObject -TypeName PSCouchDBDocument -ArgumentList '1-0033838372622627','1-2c903913030efb4d711db085b1f44107' .LINK https://pscouchdb.readthedocs.io/en/latest/classes.html #> param( [ValidateSet("PSCouchDBRequest", "PSCouchDBQuery", "PSCouchDBDocument", "PSCouchDBAttachment", "PSCouchDBBulkDocument", "PSCouchDBSecurity", "PSCouchDBReplication", "PSCouchDBView", "PSCouchDBDesignDoc")] [string] $TypeName, [array] $ArgumentList ) return New-Object -TypeName $TypeName -ArgumentList $ArgumentList } |