인쇄 용지를 문서 크기로 제시 + Select 형 배선 필터 실행 — 남은 과제 2건
① PDF 높이 어긋남(735pt vs 문서 642pt) 원인 규명·수정: 인쇄가 용지(PrintTicket)를 지정하지 않아 드라이버가 폭이 비슷한 기본 용지 (540×735pt ≈ 16절 190×260mm — test1.pdf MediaBox 실측)에 문서를 얹었다. 폭이 우연히 같아 좌우는 멀쩡하고 아래에만 33mm 여백이 붙어 화면과 다른 종이가 됐다. ShowDialog 전에 PageMediaSize 를 문서 첫 페이지 DIP 크기로 제시 — 사용자가 대화상자에서 용지를 바꾸면 그 선택이 이긴다. (레거시는 사용자가 고른 용지에 문서를 맞추는 방식 (clPrintDesignSheet.vb:660)이라 이 기본값 제시와 충돌하지 않는다.) ② Select 형 DataTableField 필터(운영 268건, 12%) 실행: 지금까지 "아직 옮기지 않았습니다" 사유였다. 필터 문법을 직접 파싱하지 않고 .NET DataTable.Select 에 그대로 넘긴다 — 레거시 배선이 쓰는 바로 그 엔진이라 문법 호환을 증명할 필요가 없다. 행 선택을 순수 함수 (DataTableFieldPicker)로 분리해 DB 없이 검증(테스트 5건 — 필터·0행· 문법 오류·Rows 형·중복 컬럼명 Fill 규칙). 알려진 한계 주석: 우리 결과는 전부 문자열 컬럼이라 숫자 대소 비교 필터는 사전순이 될 수 있다(운영 필터 대부분은 동등 비교). - dotnet test 347/347 (picker 5건 추가) · --edit-smoke 실패 0 - --db-patient ①~㊱ 전건 통과 - --db-render P062 md5 8d683835f5d81e7bb41c79071d6bf954 불변 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
31a05c205b
commit
2310971a10
@@ -0,0 +1,95 @@
|
||||
using System.Data;
|
||||
|
||||
namespace SheetMe.Core.Catalog;
|
||||
|
||||
/// <summary>
|
||||
/// 조회 결과(컬럼·행 문자열)에서 <see cref="DataTableFieldSpec"/> 이 가리키는 한 칸을 꺼낸다 —
|
||||
/// Rows 형은 행 번호로, Select 형은 <b>.NET DataTable.Select 를 그대로 호출</b>해서 고른다.
|
||||
///
|
||||
/// <b>필터 문법을 직접 파싱하지 않는다.</b> 레거시 배선의 Select 필터는 .NET
|
||||
/// <c>DataTable.Select(filterExpression)</c> 문법 그대로다 — 같은 엔진에 넘기면
|
||||
/// 문법 호환을 우리가 증명할 필요가 없다. 파서를 새로 쓰면 LIKE·괄호·이스케이프에서
|
||||
/// 조용히 갈라진다.
|
||||
///
|
||||
/// <b>알려진 한계</b>: 우리 결과는 전부 문자열 컬럼이라(레거시는 Oracle 어댑터가
|
||||
/// 실타입으로 채운다) 숫자 대소 비교 필터(예: <c>AMT > 100</c>)는 사전순이 된다.
|
||||
/// 운영 실측 필터는 대부분 동등 비교(<c>컬럼 = '값'</c>)라 실질 영향이 좁지만,
|
||||
/// 대소 비교 필터를 만나면 값이 다를 수 있다 — 그때 타입 추론을 붙인다.
|
||||
/// </summary>
|
||||
public static class DataTableFieldPicker
|
||||
{
|
||||
#region Methods
|
||||
/// <summary>한 칸의 값 — 못 고르면 사유</summary>
|
||||
public static TagValue Pick(IReadOnlyList<string> columns, IReadOnlyList<string[]> rows,
|
||||
DataTableFieldSpec spec)
|
||||
{
|
||||
var columnIndex = -1;
|
||||
for (var i = 0; i < columns.Count; i++)
|
||||
{
|
||||
if (string.Equals(columns[i], spec.Field, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
columnIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (columnIndex < 0)
|
||||
{
|
||||
return new TagValue(false, $"결과에 '{spec.Field}' 컬럼이 없습니다"
|
||||
+ $" (있는 컬럼: {string.Join(", ", columns.Take(8))})");
|
||||
}
|
||||
|
||||
if (spec.Form == DataTableFieldForm.Select && spec.Filter.Length > 0)
|
||||
{
|
||||
using var table = new DataTable();
|
||||
foreach (var name in columns)
|
||||
{
|
||||
// SELECT * 조인은 컬럼명이 겹칠 수 있다 — Oracle 어댑터의 Fill 과 같은
|
||||
// 규칙(이름1, 이름2 …)으로 비껴 담는다. spec.Field 는 첫 것과 매칭된다.
|
||||
var unique = name;
|
||||
var suffix = 1;
|
||||
while (table.Columns.Contains(unique))
|
||||
{
|
||||
unique = name + suffix.ToString(System.Globalization.CultureInfo.InvariantCulture);
|
||||
suffix++;
|
||||
}
|
||||
table.Columns.Add(unique, typeof(string));
|
||||
}
|
||||
foreach (var row in rows)
|
||||
{
|
||||
table.Rows.Add(row.Select(object (c) => c ?? string.Empty).ToArray());
|
||||
}
|
||||
DataRow[] picked;
|
||||
try
|
||||
{
|
||||
picked = table.Select(spec.Filter);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 필터 문법이 깨졌다 — 레거시 런타임은 빈 catch 로 삼켜 빈칸이 됐다
|
||||
return new TagValue(false, $"Select 필터를 해석할 수 없습니다: {ex.Message}");
|
||||
}
|
||||
if (spec.RowIndex >= picked.Length)
|
||||
{
|
||||
return new TagValue(false, picked.Length == 0
|
||||
? $"필터({spec.Filter})에 맞는 행이 없습니다"
|
||||
: $"{spec.RowIndex}번 행이 없습니다(필터 결과 {picked.Length}행)");
|
||||
}
|
||||
var filtered = picked[spec.RowIndex][columnIndex]?.ToString() ?? string.Empty;
|
||||
return filtered.Length > 0
|
||||
? new TagValue(true, filtered)
|
||||
: new TagValue(false, $"{spec.Field} 값이 비어 있습니다");
|
||||
}
|
||||
|
||||
if (spec.RowIndex >= rows.Count)
|
||||
{
|
||||
return new TagValue(false, rows.Count == 0
|
||||
? "조회 결과가 0행입니다"
|
||||
: $"{spec.RowIndex}번 행이 없습니다(결과 {rows.Count}행)");
|
||||
}
|
||||
var cell = rows[spec.RowIndex][columnIndex] ?? string.Empty;
|
||||
return cell.Length > 0
|
||||
? new TagValue(true, cell)
|
||||
: new TagValue(false, $"{spec.Field} 값이 비어 있습니다");
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
Reference in New Issue
Block a user