Skip to content

fix: lazy-load full values for truncated columns in detail pane#446

Merged
datlechin merged 4 commits intomainfrom
fix/lazy-load-truncated-columns
Mar 24, 2026
Merged

fix: lazy-load full values for truncated columns in detail pane#446
datlechin merged 4 commits intomainfrom
fix/lazy-load-truncated-columns

Conversation

@datlechin
Copy link
Collaborator

@datlechin datlechin commented Mar 24, 2026

Summary

  • Problem: ColumnExclusionPolicy truncates LONGTEXT/MEDIUMTEXT/CLOB columns to 256 chars via SUBSTRING() in browse queries for performance. The detail pane (right sidebar) displayed these truncated values for editing — saving would silently overwrite the full DB value with truncated data.
  • Fix: When a row is selected, fire a targeted SELECT col FROM table WHERE pk = ? to fetch full values for excluded columns, then patch them into the sidebar edit state.
  • Sidebar shows a loading spinner during fetch, and an orange "truncated" badge if fetch fails or no PK is available (editing disabled in that case).
  • Safety guard in getEditedFields() prevents saving any field still marked as truncated.

Test plan

  • 11 new tests in MultiRowEditStateTruncationTests — all pass
  • Existing MultiRowEditStateTests — all pass (no regressions)
  • Existing ColumnExclusionPolicyTests — all pass
  • Build succeeds
  • Manual: browse MySQL/PostgreSQL table with LONGTEXT column → select row → sidebar loads full value → edit and save → verify full value persisted
  • Manual: table without PK → sidebar shows "truncated" badge, field disabled

Summary by CodeRabbit

  • New Features

    • Detail pane now lazy-loads full values for long-text columns and shows a loading indicator while fetching.
  • Bug Fixes

    • Resolved issue where truncated long-text values prevented correct editing in the detail pane.
  • Documentation

    • Changelog updated to reflect the lazy-loading and fix.

@coderabbitai
Copy link

coderabbitai bot commented Mar 24, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a67afe41-d197-406c-9c3b-7b4ea6cd20fc

📥 Commits

Reviewing files that changed from the base of the PR and between 4e14162 and b217d63.

📒 Files selected for processing (2)
  • TablePro/Views/Main/Extensions/MainContentCoordinator+LazyLoadColumns.swift
  • TablePro/Views/Main/MainContentView.swift
🚧 Files skipped from review as they are similar to previous changes (1)
  • TablePro/Views/Main/MainContentView.swift

📝 Walkthrough

Walkthrough

Adds UI and state plumbing to lazy-load full values for excluded/truncated LONGTEXT/MEDIUMTEXT/CLOB columns: state flags, coordinator DB fetch, main view async flow to apply results, editor UI changes to show truncated/loading states, tests, and changelog/localization entries.

Changes

Cohort / File(s) Summary
State Management
TablePro/Models/UI/MultiRowEditState.swift
Made FieldEditState.originalValue mutable; added isTruncated and isLoadingFullValue flags. configure(..., excludedColumnNames:) marks excluded fields as truncated/loading and preserves resolved values across re-configures. Added applyFullValues(_:). getEditedFields() now excludes truncated fields.
Coordinator & Database
TablePro/Views/Main/Extensions/MainContentCoordinator+LazyLoadColumns.swift
New internal async method fetchFullValuesForExcludedColumns(...) that builds a parameterized SELECT for quoted excluded columns by primary key and returns a [String: String?] map of column→value.
Main View Integration
TablePro/Views/Main/MainContentView.swift
Added lazyLoadTask for cancellable async fetch. Passes excludedColumnNames into edit-state configure(...). When exactly one row is selected, triggers coordinator fetch and applies results with applyFullValues(...); clears loading flags on error or context change.
UI Components
TablePro/Views/RightSidebar/EditableFieldView.swift, TablePro/Views/RightSidebar/RightSidebarView.swift
EditableFieldView gains isTruncated and isLoadingFullValue inputs. Renders orange “truncated” badge, disabled loading editor with spinner, or read-only message for truncated fields. RightSidebarView wires these flags from FieldEditState.
Localization
TablePro/Resources/Localizable.xcstrings
Added new localization key \"truncated\" (empty object entry).
Documentation
CHANGELOG.md
Added Unreleased entries describing lazy-loading of full values for very-long text columns and a fix for previously truncated values preventing correct editing.
Tests
TableProTests/Models/MultiRowEditStateTruncationTests.swift
New test suite covering truncation defaults, configure(..., excludedColumnNames:) behavior, applyFullValues(...) (including nil handling and pending-value preservation), and ensuring truncated fields are excluded from getEditedFields().

Sequence Diagram(s)

sequenceDiagram
    participant UI as MainContentView
    participant State as MultiRowEditState
    participant Coordinator as MainContentCoordinator
    participant DB as Database
    participant Editor as EditableFieldView

    UI->>State: configure(excludedColumnNames: Set)
    State->>State: mark fields with isTruncated=true\nisLoadingFullValue=true

    Note over UI: single-row selection
    UI->>Coordinator: fetchFullValuesForExcludedColumns(table, pkCol, pkVal, excluded)
    Coordinator->>DB: execute parameterized SELECT for excluded columns
    DB-->>Coordinator: row with full values
    Coordinator-->>UI: [columnName: value] dictionary

    UI->>State: applyFullValues(fullValues)
    State->>State: update originalValue\nset isTruncated=false\nset isLoadingFullValue=false

    State-->>Editor: propagate flags and values
    Editor->>Editor: render full value / spinner / truncated badge
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~55 minutes

Possibly related PRs

Poem

🐰 I hopped through rows both short and long,
Spun a spinner, hummed a song,
Fetched the carrots—full and bright,
No more truncation in the night! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: lazy-loading full values for truncated columns in the detail pane sidebar, which matches the core problem statement and solution in the PR objectives.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/lazy-load-truncated-columns

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@TablePro/Views/Main/Extensions/MainContentCoordinator`+LazyLoadColumns.swift:
- Around line 14-15: The extension for MainContentCoordinator lacks an explicit
access control modifier; update the extension declaration (extension
MainContentCoordinator) to include the repository's required modifier (for
example use "internal extension MainContentCoordinator") so the extension itself
has an explicit access level while leaving individual members unchanged; locate
the extension containing the function fetchFullValuesForExcludedColumns and add
the access modifier there.
- Line 41: Remove the hardcoded "LIMIT 1" from the SQL string built with
quotedCols, quotedTable, quotedPK and placeholder in the query assignment so the
code does not rely on a SQL dialect-specific clause (the primary-key predicate
already guarantees a single row); also add an explicit access control modifier
to the extension declaration by changing the extension to "private extension
MainContentCoordinator {" (or "internal"/"public" if broader visibility is
required).

In `@TablePro/Views/Main/MainContentView.swift`:
- Around line 937-956: The error handler can modify fields of a new selection if
the row changed while the lazyLoadTask awaited; to fix, capture an immutable
identifier for the targeted selection (e.g., pkValue or a generated
selectionToken) before calling
capturedCoordinator.fetchFullValuesForExcludedColumns in the Task and then, in
both the success path (before applyFullValues) and the catch path (before
clearing isLoadingFullValue on capturedEditState.fields), check that the current
selection still matches that captured identifier; only applyFullValues or reset
loading flags when the identifiers match, otherwise no-op to avoid touching the
new selection’s fields (update code near lazyLoadTask,
capturedCoordinator.fetchFullValuesForExcludedColumns,
capturedEditState.applyFullValues and the catch block that iterates
capturedEditState.fields).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: be5b25cd-94ff-48ab-9985-d777fadf6a61

📥 Commits

Reviewing files that changed from the base of the PR and between 64d13cd and 629fdfc.

📒 Files selected for processing (9)
  • CHANGELOG.md
  • TablePro.xcodeproj/project.pbxproj
  • TablePro/Models/UI/MultiRowEditState.swift
  • TablePro/Resources/Localizable.xcstrings
  • TablePro/Views/Main/Extensions/MainContentCoordinator+LazyLoadColumns.swift
  • TablePro/Views/Main/MainContentView.swift
  • TablePro/Views/RightSidebar/EditableFieldView.swift
  • TablePro/Views/RightSidebar/RightSidebarView.swift
  • TableProTests/Models/MultiRowEditStateTruncationTests.swift

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
TablePro/Models/UI/MultiRowEditState.swift (1)

224-225: Declare the new mutation API's access level explicitly.

applyFullValues(_:) currently relies on Swift's default internal. Please spell the intended visibility out here so this new edit-state entry point follows the repo convention, then rerun swiftlint lint --strict. As per coding guidelines, "Always use explicit access control modifiers (private, internal, public). Specify access modifier on extension, not individual members".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@TablePro/Models/UI/MultiRowEditState.swift` around lines 224 - 225, The new
mutation API method applyFullValues(_:) currently has implicit internal
visibility; update the access control by adding an explicit access modifier to
the extension that contains applyFullValues (e.g., mark the extension as
internal or public per the repo convention) rather than annotating individual
members so the new edit-state entry point follows the guideline "Specify access
modifier on extension, not individual members", then re-run swiftlint lint
--strict to verify.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@TablePro/Models/UI/MultiRowEditState.swift`:
- Around line 125-138: The pending-edit preservation is comparing
oldField.originalValue to the rebuilt truncated originalValue (causing saved
edits to be dropped after applyFullValues(_:)); update the preservation check in
MultiRowEditState (inside the configure/field-rebuild logic) to compare
oldField.originalValue against the effective preservedOriginalValue used when
preserving full values (and still verify oldField.hasMultipleValues ==
hasMultipleValues) so pendingValue/isPendingNull/isPendingDefault are copied
only when oldField matches the actual preserved original value rather than the
truncated one.

---

Nitpick comments:
In `@TablePro/Models/UI/MultiRowEditState.swift`:
- Around line 224-225: The new mutation API method applyFullValues(_:) currently
has implicit internal visibility; update the access control by adding an
explicit access modifier to the extension that contains applyFullValues (e.g.,
mark the extension as internal or public per the repo convention) rather than
annotating individual members so the new edit-state entry point follows the
guideline "Specify access modifier on extension, not individual members", then
re-run swiftlint lint --strict to verify.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 96b1e79a-d42b-48e2-aafc-df1297af9288

📥 Commits

Reviewing files that changed from the base of the PR and between 629fdfc and 4e14162.

📒 Files selected for processing (4)
  • TablePro/Models/UI/MultiRowEditState.swift
  • TablePro/Views/Main/Extensions/MainContentCoordinator+LazyLoadColumns.swift
  • TablePro/Views/Main/MainContentView.swift
  • TablePro/Views/RightSidebar/EditableFieldView.swift
🚧 Files skipped from review as they are similar to previous changes (3)
  • TablePro/Views/RightSidebar/EditableFieldView.swift
  • TablePro/Views/Main/MainContentView.swift
  • TablePro/Views/Main/Extensions/MainContentCoordinator+LazyLoadColumns.swift

@datlechin datlechin merged commit 96bcd12 into main Mar 24, 2026
3 checks passed
@datlechin datlechin deleted the fix/lazy-load-truncated-columns branch March 24, 2026 15:09
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