src/metadata/GraphSegment.ps1
# Copyright 2021, Adam Edwards # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. . (import-script EntityVertex) ScriptClass GraphSegment { $graphElement = $null $leadsToVertex = $false $name = $null $type = $null $isDynamic = $false $parent = $null $isVirtual = $false $isInVirtualPath = $false $graphUri = $null $decoration = $null function __initialize($graphElement, $parent = $null, $instanceName = $null) { $this.graphElement = $graphElement $this.parent = if ( $parent ) { $parent } else { $::.GraphSegment.RootSegment } $isVertex = $true $this.leadsToVertex = if ( Test-ScriptObject $this.graphElement EntityEdge ) { $isVertex = $false if ( $instanceName -and $graphElement.Name -ne $instanceName ) { throw "An instance name '$instanceName' was specified for an edge, and if it is specified it must match the existing name for this edge '$($graphElement.Name)', which it does not." } $this.type = $this.graphElement.transition.type # If this is one to many, then the next element is an individual vertex. Otherwise, # the node is another (named) transition $this.graphElement.oneToMany } else { $this.type = ($this.graphElement.type) $this.graphElement.type -eq 'EntitySet' } $this.name = if ( $isVertex -and ($this.graphElement |=> IsRoot) ) { '/' } elseif ( $this.leadsToVertex -or ($isVertex -and $this.graphElement.type -eq 'Singleton') ) { $this.graphElement.name } elseif ( $instanceName ) { $this.isDynamic = $true $instanceName } elseif (! $isVertex -and ! $this.leadsToVertex ) { # This is an edge, but instead of leading to a vertex, it leads to another edge $this.graphElement.name } else { $this.isDynamic = $true $this.isVirtual = $true "{{{0}}}" -f $this.graphElement.name } $this.isInVirtualPath = $this.isVirtual -or ( $parent -ne $null -and $parent.IsInVirtualPath ) $this.GraphUri = if ( $this.parent ) { $::.GraphUtilities.JoinFragmentUri($this.parent.graphUri, $this.name) } else { $this.name } } function Decorate($data) { if ($this.decoration) { throw 'Segment already has decoration data' } $this.decoration = $data } function NewVertexSegment($graph, $segmentName, $allowedVertexTypes) { if ( ! $this.leadsToVertex ) { throw "Vertex segment instance name may not be supplied for '$($this.graphElement.id)', segments are pre-defined" } $graphElement = if ( Test-ScriptObject $this.graphElement EntityEdge ) { if ( $this.GraphElement.sink |=> IsNull ) { return $null } else { $this.GraphElement.sink } } elseif ( $this.graphElement.type -eq 'EntitySet' ) { $typeData = $this.graphElement.entity.typeData $graph |=> GetTypeVertex $typeData.TypeName } else { throw "Unexpected vertex type '$($this.graphElement.type)' for segment '$($segment.name)'" } if ( ! $graphElement ) { throw "Unable to determine element type for '$($this.graphElement)' for segment '$($segment.name)'" } if ( $allowedVertexTypes -and ($graphElement.Type -notin $allowedVertextypes) ) { return $null } new-so GraphSegment $graphElement $this $segmentName } function NewTransitionSegments($graph, $segmentName, $allowedTransitionTypes = $null) { if ( $this.leadsToVertex ) { throw "Current segment $($this.graphElement.name) is static, so next segment must be dynamic" } $isVertex = Test-ScriptObject $this.graphElement EntityVertex $edges = if ( $isVertex ) { $localEdges = $graph |=> GetVertexEdges $this.graphElement if ( $segmentName -and $segmentName -ne '' ) { $localEdges[$segmentName] } else { $localEdges.values } } else { # This is already an edge, so the next edges come from the sink $sinkEdges = $graph |=> GetVertexEdges $this.GraphElement.sink if ( ! ( $this.graphElement.sink |=> IsNull ) ) { $sinkEdges.values } } $edges | foreach { if ( ! $allowedTransitionTypes -or ($_.transition.type -in $allowedTransitionTypes) ) { new-so GraphSegment $_ $this } } } function NewNextSegments($graph, $segmentName, $allowedTransitionTypes) { if ( $this.leadsToVertex ) { $newVertex = NewVertexSegment $graph $segmentName $allowedTransitionTypes if ( $newVertex ) { $newVertex } else { @() } } else { NewTransitionSegments $graph $segmentName $allowedTransitionTypes } } function IsRoot { (Test-ScriptObject $this.GraphElement EntityVertex) -and ($this.GraphElement |=> IsRoot) } function ToGraphUri($graph = $null) { if ( ! $graph ) { ToGraphUriFromEndpoint } else { ToGraphUriFromEndpoint $graph.Endpoint $graph.ApiVersion } } function ToGraphUriFromEndpoint($graphEndpointUri = $null, $graphVersion = $null) { $currentSegment = $this $relativeUriString = $this.name while ($currentSegment.parent -ne $null) { $relativeUriString = $::.GraphUtilities.JoinFragmentUri($currentSegment.parent.name, $relativeUriString) $currentSegment = $currentSegment.parent } if ( ! $graphEndpointUri ) { $::.GraphUtilities.JoinGraphUri('/', $relativeUriString) } else { $relativeVersionedUriString = $::.GraphUtilities.JoinRelativeUri($graphVersion, $relativeUriString) $::.GraphUtilities.JoinAbsoluteUri($graphEndpointUri, $relativeVersionedUriString) } } static { $RootSegment = $null $NullSegment = $null } } $::.GraphSegment.RootSegment = new-so GraphSegment $::.EntityVertex.RootVertex $::.GraphSegment.NullSegment = new-so GraphSegment $::.Entityvertex.NullVertex |