Skip to content

fix(datagrid): repair three broken Preview Referenced Row paths - #2324

Merged
datlechin merged 2 commits into
mainfrom
fix/foreign-key-preview-defects
Aug 21, 2026
Merged

fix(datagrid): repair three broken Preview Referenced Row paths#2324
datlechin merged 2 commits into
mainfrom
fix/foreign-key-preview-defects

Conversation

@datlechin

Copy link
Copy Markdown
Member

Three defects found while investigating #2316 and reported on #2323. All three break Preview Referenced Row, none of them was needed for that fix, and each fails in a way that looks like a foreign key pointing at nothing rather than like a bug.

1. The menu command read the wrong column

MainContentCoordinator.toggleFKPreviewForFocusedCell turned focusedColumn into a data index by subtracting 1. focusedColumn is a position in tableView.tableColumns, which carries the row-number column and a hidden spacer ahead of the data, so data index N sits at table column N+2. The offset was wrong before the reader touched anything, and reordering a column moved it again.

Query > Preview FK Reference therefore previewed a different column than the focused one, or failed its bounds guard and did nothing at all, while Space on the same cell worked: the key-equivalent path in KeyHandlingTableView already resolves by column identity through DataGridView.dataColumnIndex(for:in:schema:). The menu path now uses the same two calls.

2. The lookup was invalid SQL on SQL Server

ForeignKeyPreviewView emitted OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY with no ORDER BY. T-SQL parses OFFSET/FETCH as part of an ORDER BY clause, so SQL Server rejects the statement with Msg 102. Every other .offsetFetch consumer reads dialect.offsetFetchOrderBy first (FilterSQLGenerator.swift:485, TableQueryBuilder), and MSSQL keeps the default ORDER BY (SELECT NULL).

The catch replaced the server's message with the generic "Failed to load referenced row", and because values stayed empty the popover's Open button was disabled too, so the whole popover was inert on every SQL Server connection.

The clause now comes from the dialect. The statement moved into ForeignKeyPreviewQuery, a pure builder, so the clause order can be pinned by a test instead of living inside a SwiftUI view's async method.

3. The iOS fork hardcoded LIMIT 1

TableProMobile's FKPreviewView built ... LIMIT 1 directly, which both SQL Server and Oracle reject, and both ship in IOSDriverFactory.supportedTypes. SQLBuilder.paginationClause already handles those two engines and was simply not called; it is now.

The same view swallowed the failure into row = nil, which renders ContentUnavailableView("No Referenced Row"), indistinguishable from a key with no matching row. A preview that fails now says so and shows the reason, and the "no row" state means only that.

What I built and tested

  • macOS: verify.sh build PASS, verify.sh test over ForeignKeyPreviewQueryTests, FocusedColumnResolutionTests, FKNavigationTests, DataGridColumnPoolTests and ColumnIdentitySchemaTests PASS at 79/79, verify.sh lint TablePro TableProTests TableProMobile 0 violations.
  • iOS: xcodebuild -scheme TableProMobile -destination 'platform=iOS Simulator,name=iPhone 17 Pro Max' ARCHS=arm64 BUILD SUCCEEDED, and SQLBuilderPaginationTests + SQLDialectParityTests pass on the simulator.

New tests:

  • ForeignKeyPreviewQueryTests: the OFFSET/FETCH clause carries its ORDER BY filler, a dialect that declares no filler emits the clause alone, a LIMIT dialect and an absent dialect both get LIMIT 1, the statement ends with the clause, and an already-escaped value is not escaped twice.
  • FocusedColumnResolutionTests: builds a real grid through DataGridColumnPool, then asserts a data column does not sit one place after its data index, that every column round-trips, that reordering moves a column without changing what it resolves to, and that the row-number column is not a data column. The first of those fails against the old - 1 mapping.
  • SQLBuilderPaginationTests (iOS): SQL Server and Oracle each get OFFSET/FETCH behind their own filler ORDER BY and never LIMIT, a caller's own order replaces the filler instead of stacking with it, the LIMIT engines get LIMIT n OFFSET n, and every type IOSDriverFactory ships produces a clause its engine can parse.

Note

None of these needed #2316's fix and none is needed by it; this is separate work on the same subsystem, opened after that PR merged.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

Signed-off-by: Ngô Quốc Đạt <datlechin@gmail.com>
@datlechin
datlechin merged commit 3372937 into main Aug 21, 2026
5 of 6 checks passed
@datlechin
datlechin deleted the fix/foreign-key-preview-defects branch August 21, 2026 09:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant