HarperFast / HarperFast/studio
Browse: elements-less array column named like a table is mis-rendered as a relationship
- Dominant language
- TypeScript
- Stars
- 5
- Forks
- 4
- Avg merge
- 1d 8h
- Merged PRs (30d)
- 40
Description
## Summary
In the database browse view, a **plain array column** can be mis-rendered as a to-many relationship (a `Table →` reverse-link chip) when it has no element type in `describe_table` **and** happens to be named like a sibling table. Flagged by @DavidCockerill in review of #1438 as low-priority / non-blocking.
## Where
`src/features/instance/databases/functions/relationshipAttributes.ts` → `relatedTableNameOf()` → `findSiblingTableByName()`. For an attribute reported by `describe_table` as `{ type: 'array' }` with **no `elements`**, we match its name (and simple singular/plural variants) against sibling table names and treat it as a to-many relationship. Regression coverage that pins the current behavior: the "legacy elements-less relationships and reverse foreign keys" block in `relationshipAttributes.test.ts`.
Only **elements-less** arrays are affected. Typed scalar arrays (`elements: 'String'`) and typed to-many relationships (`elements: ''`) are unambiguous and unaffected.
## Why it's a false positive (analysis)
Walking the two server regimes, an elements-less array in `describe_table` is **never** a Harper-modeled relationship:
- **Harper 5.1+**: relationship attributes are omitted from `describe_table` entirely (see #1438 / the describe regression). So anything that *does* appear as `{ type: 'array' }` is a persisted plain/legacy array column, not a relationship → name match = false positive.
- **Harper 4.x**: to-many relationships appear in describe with `elements` **typed** (e.g. `reviews: [Review]` → `{ type: 'array', elements: 'Review' }`, verified against 4.7.28). A real to-many is therefore caught by the typed path, not the elements-less name heuristic.
So the elements-less name heuristic has no regime where it catches a relationship Harper actually models — it only ever fires on plain array data. The `data.Albums.tracks` case that motivated it "worked" by luck: `Tracks.albumId` lined up by convention, but `tracks` was not a declared `@relationship`.
Real relationships are already covered without the heuristic: schema-declared ones via `schemaRelationships.ts` (exact `from:`/`to:`, the only source on 5.1) and typed to-many via describe on 4.x.
## Options
1. **Remove the elements-less name heuristic** (`findSiblingTableByName`) — rely solely on schema-declared relationships + elements-typed describe. Removes the false positive at the root. Only behavior change: an un-declared elements-less array named like a table renders as plain JSON instead of a guessed reverse-link. Schema-declared to-many (e.g. `Category.products`) is unaffected (detected via schema, not this heuristic). **Recommended.**
2. **Gate on schema presence** — apply the heuristic only to tables absent from all parsed component schemas. More conservative but keeps a guess for truly schema-less data.
3. **Corroborate** — only treat an elements-less array as a relationship if the sibling table has a plausible reverse foreign key back-referencing this table. Narrows but doesn't eliminate false positives; couples detection to reverse-key inference.
Recommendation: option 1. If we want to keep a best-effort link for schema-less legacy data, option 2.
## Not urgent
The column def, header, and data are all still present either way; the only impact is a plain array being shown as a link chip instead of JSON. No data correctness or write-path impact.
Contributor guide
Research direction
Start in src/features/instance/databases/functions/relationshipAttributes.ts at relatedTableNameOf() and findSiblingTableByName(), then inspect the legacy elements-less relationships and reverse foreign keys block in relationshipAttributes.test.ts. Ensure elements-less plain arrays render as data while schema-declared and elements-typed relationships remain supported, and update the regression coverage to verify the distinction.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- databases, frontend
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- Half a day
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 84/100