Files
llm/scripts/validate_1c_predicted_columns.ps1
T

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