222 lines
9.1 KiB
PowerShell
222 lines
9.1 KiB
PowerShell
param(
|
|
[string]$Server = $env:ONEC_SQL_SERVER,
|
|
[string]$Database = $env:ONEC_SQL_DATABASE,
|
|
[string]$User = $env:ONEC_SQL_USER,
|
|
[string]$Password = $env:ONEC_SQL_PASSWORD,
|
|
[string]$SummaryPath,
|
|
[string]$OutputPath
|
|
)
|
|
|
|
Set-StrictMode -Version Latest
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
if (-not $Server) { throw "Server is required. Use -Server or ONEC_SQL_SERVER." }
|
|
if (-not $Database) { throw "Database is required. Use -Database or ONEC_SQL_DATABASE." }
|
|
if (-not $User) { throw "User is required. Use -User or ONEC_SQL_USER." }
|
|
if (-not $Password) { throw "Password is required. Use -Password or ONEC_SQL_PASSWORD." }
|
|
if (-not $SummaryPath) { throw "SummaryPath is required." }
|
|
if (-not $OutputPath) { throw "OutputPath is required." }
|
|
|
|
$metadataFields = @(
|
|
"attributes", "tabular_sections", "dimensions", "resources", "forms",
|
|
"templates", "commands", "addressing_attributes", "accounting_flags",
|
|
"columns", "enum_values", "integration_service_channels", "operations",
|
|
"url_templates"
|
|
"tabular_section_attributes"
|
|
)
|
|
|
|
$summary = Get-Content -LiteralPath $SummaryPath -Raw -Encoding UTF8 | ConvertFrom-Json
|
|
$checks = New-Object System.Collections.Generic.List[object]
|
|
$tableChecks = New-Object System.Collections.Generic.List[object]
|
|
|
|
foreach ($row in $summary.outputs) {
|
|
$report = Get-Content -LiteralPath $row.output -Raw -Encoding UTF8 | ConvertFrom-Json
|
|
$tables = @($report.object_storage_routes | Where-Object { $_.route_kind -eq "table" -and $_.physical_name_candidate } | ForEach-Object { $_.physical_name_candidate })
|
|
foreach ($field in $metadataFields) {
|
|
if (-not ($report.PSObject.Properties.Name -contains $field)) { continue }
|
|
foreach ($item in @($report.$field)) {
|
|
$itemCandidateTables = $tables
|
|
if ($item.PSObject.Properties.Name -contains "parent_physical_tables") {
|
|
$parentTables = @($item.parent_physical_tables | Where-Object { $_.PSObject.Properties.Name -contains "table" -and $_.table } | ForEach-Object { $_.table })
|
|
if ($parentTables.Count -gt 0) {
|
|
$itemCandidateTables = $parentTables
|
|
}
|
|
}
|
|
foreach ($column in @($item.physical_columns | Where-Object { $_.PSObject.Properties.Name -contains "column" -and $_.column })) {
|
|
$checks.Add([pscustomobject]@{
|
|
kind = $report.kind
|
|
object_name = $report.identity.name
|
|
object_guid = $report.identity.guid
|
|
metadata_field = $field
|
|
item_name = $item.name
|
|
item_guid = $item.uuid
|
|
value_type = if ($column.PSObject.Properties.Name -contains "value_type") { $column.value_type } elseif ($column.PSObject.Properties.Name -contains "value_types") { ($column.value_types -join ",") } else { $null }
|
|
predicted_column = $column.column
|
|
candidate_tables = $itemCandidateTables
|
|
})
|
|
}
|
|
$physicalTables = @()
|
|
if ($item.PSObject.Properties.Name -contains "physical_tables") {
|
|
$physicalTables = @($item.physical_tables)
|
|
}
|
|
foreach ($tableCandidate in @($physicalTables | Where-Object { $_.PSObject.Properties.Name -contains "table" -and $_.table })) {
|
|
$tableChecks.Add([pscustomobject]@{
|
|
kind = $report.kind
|
|
object_name = $report.identity.name
|
|
object_guid = $report.identity.guid
|
|
metadata_field = $field
|
|
item_name = $item.name
|
|
item_guid = $item.uuid
|
|
predicted_table = $tableCandidate.table
|
|
reason = $tableCandidate.reason
|
|
})
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$connectionString = "Server=$Server;Database=$Database;User ID=$User;Password=$Password;Encrypt=False;TrustServerCertificate=True;Application Name=Codex 1C Column Prediction Validation;"
|
|
$connection = [System.Data.SqlClient.SqlConnection]::new($connectionString)
|
|
|
|
$results = New-Object System.Collections.Generic.List[object]
|
|
$foundCount = 0
|
|
|
|
try {
|
|
$connection.Open()
|
|
$allTables = @(
|
|
@($checks | ForEach-Object { $_.candidate_tables } | Where-Object { $_ })
|
|
@($tableChecks | ForEach-Object { $_.predicted_table } | Where-Object { $_ })
|
|
) | Select-Object -Unique
|
|
$schemaLookup = @{}
|
|
if ($allTables.Count -gt 0) {
|
|
$command = $connection.CreateCommand()
|
|
$command.CommandTimeout = 0
|
|
$tableParams = @()
|
|
for ($i = 0; $i -lt $allTables.Count; $i++) {
|
|
$name = "@t$i"
|
|
$tableParams += $name
|
|
$null = $command.Parameters.Add($name, [System.Data.SqlDbType]::NVarChar, 128)
|
|
$command.Parameters[$name].Value = $allTables[$i]
|
|
}
|
|
$command.CommandText = @"
|
|
SELECT TABLE_NAME, COLUMN_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION, NUMERIC_SCALE, IS_NULLABLE
|
|
FROM INFORMATION_SCHEMA.COLUMNS
|
|
WHERE TABLE_NAME IN ($($tableParams -join ","))
|
|
"@
|
|
$reader = $command.ExecuteReader()
|
|
try {
|
|
while ($reader.Read()) {
|
|
$item = [pscustomobject]@{
|
|
table = [string]$reader.GetValue(0)
|
|
column = [string]$reader.GetValue(1)
|
|
data_type = [string]$reader.GetValue(2)
|
|
max_length = if ($reader.IsDBNull(3)) { $null } else { $reader.GetValue(3) }
|
|
precision = if ($reader.IsDBNull(4)) { $null } else { $reader.GetValue(4) }
|
|
scale = if ($reader.IsDBNull(5)) { $null } else { $reader.GetValue(5) }
|
|
nullable = [string]$reader.GetValue(6)
|
|
}
|
|
$key = "$($item.table)|$($item.column)"
|
|
if (-not $schemaLookup.ContainsKey($key)) {
|
|
$schemaLookup[$key] = New-Object System.Collections.Generic.List[object]
|
|
}
|
|
$schemaLookup[$key].Add($item)
|
|
}
|
|
}
|
|
finally {
|
|
if ($reader -ne $null) {
|
|
$reader.Close()
|
|
$reader.Dispose()
|
|
}
|
|
if ($command -ne $null) { $command.Dispose() }
|
|
}
|
|
}
|
|
|
|
foreach ($check in $checks) {
|
|
$matches = New-Object System.Collections.Generic.List[object]
|
|
foreach ($table in @($check.candidate_tables)) {
|
|
$key = "$table|$($check.predicted_column)"
|
|
if ($schemaLookup.ContainsKey($key)) {
|
|
foreach ($match in $schemaLookup[$key]) {
|
|
$matches.Add($match)
|
|
}
|
|
}
|
|
}
|
|
if ($matches.Count -gt 0) { $foundCount++ }
|
|
$results.Add([pscustomobject]@{
|
|
kind = $check.kind
|
|
object_name = $check.object_name
|
|
object_guid = $check.object_guid
|
|
metadata_field = $check.metadata_field
|
|
item_name = $check.item_name
|
|
item_guid = $check.item_guid
|
|
value_type = $check.value_type
|
|
predicted_column = $check.predicted_column
|
|
candidate_tables = $check.candidate_tables
|
|
found = $matches.Count -gt 0
|
|
matches = $matches
|
|
})
|
|
}
|
|
}
|
|
finally {
|
|
if ($connection -ne $null) { $connection.Dispose() }
|
|
}
|
|
|
|
$byKind = $results | Group-Object kind | ForEach-Object {
|
|
[pscustomobject]@{
|
|
kind = $_.Name
|
|
predicted_count = $_.Count
|
|
found_count = @($_.Group | Where-Object found).Count
|
|
}
|
|
}
|
|
|
|
$tableResults = New-Object System.Collections.Generic.List[object]
|
|
$tableFoundCount = 0
|
|
foreach ($check in $tableChecks) {
|
|
$exists = $false
|
|
foreach ($key in $schemaLookup.Keys) {
|
|
if ($key.StartsWith("$($check.predicted_table)|")) {
|
|
$exists = $true
|
|
break
|
|
}
|
|
}
|
|
if ($exists) { $tableFoundCount++ }
|
|
$tableResults.Add([pscustomobject]@{
|
|
kind = $check.kind
|
|
object_name = $check.object_name
|
|
object_guid = $check.object_guid
|
|
metadata_field = $check.metadata_field
|
|
item_name = $check.item_name
|
|
item_guid = $check.item_guid
|
|
predicted_table = $check.predicted_table
|
|
reason = $check.reason
|
|
found = $exists
|
|
})
|
|
}
|
|
|
|
$tableByKind = $tableResults | Group-Object kind | ForEach-Object {
|
|
[pscustomobject]@{
|
|
kind = $_.Name
|
|
predicted_count = $_.Count
|
|
found_count = @($_.Group | Where-Object found).Count
|
|
}
|
|
}
|
|
|
|
$report = [pscustomobject]@{
|
|
schema = "onec_predicted_column_validation.v1"
|
|
summary = $SummaryPath
|
|
database = $Database
|
|
predicted_count = $checks.Count
|
|
found_count = $foundCount
|
|
predicted_table_count = $tableChecks.Count
|
|
found_table_count = $tableFoundCount
|
|
by_kind = $byKind
|
|
table_by_kind = $tableByKind
|
|
results = $results
|
|
table_results = $tableResults
|
|
}
|
|
|
|
$resolvedOutput = [System.IO.Path]::GetFullPath($OutputPath)
|
|
New-Item -ItemType Directory -Force -Path ([System.IO.Path]::GetDirectoryName($resolvedOutput)) | Out-Null
|
|
$report | ConvertTo-Json -Depth 12 | Out-File -LiteralPath $resolvedOutput -Encoding UTF8
|
|
$report | Select-Object schema, predicted_count, found_count, predicted_table_count, found_table_count | ConvertTo-Json -Compress
|