Skip to content

Relationship-options read primitive + serverAction op (bounded, projected, selected-seeded) #630

Description

@borisno2

What to build

The Relationship options read primitive plus the server-action op that exposes it — the bounded, projected fetch that replaces the unbounded findMany({}) currently used to populate relationship editors.

getRelationshipOptions(context, relatedListKey, { search?, take?, selectedIds? }): Promise<{ id: string; label: string }[]> in stack-ui:

  • Builds a scalar-only fragment ({ id: true, [labelField]: true }, label field from getLabelFieldName) and reads through the existing context.db.* fragment query path. Because the fragment selects no relations, buildIncludeWithAccessControl is bypassed — the depth-5 auto-include and its Field Visibility walk never happen.
  • where: contains on the label field when it is a text field; otherwise no filter (first-N).
  • orderBy: label field ascending.
  • take: bounded window.
  • Always unions the currently-selected id(s) (where: { id: { in: selectedIds } }) so the caller can render the current value even when it falls outside the search/take window.
  • Maps rows through getItemLabel. Operation-level query access on the related list still applies (denied → []).

Expose it through the generic action the host already wires: a { type: 'relationshipOptions', listKey, field, search, take, selectedIds } op on context.serverAction, so there is one wiring point and one access boundary. No UI consumers change in this slice — that is #2b.

This rides the existing fragment seam only; no change to the core read path, no ADR-0001 conflict, Field Visibility intact.

Acceptance criteria

  • getRelationshipOptions returns { id, label }[] via a scalar-only fragment
  • Result is bounded by take
  • Currently-selected id(s) are present in the result even when beyond take / not matching search
  • search filters via contains on the resolved label field; ordering is by that field
  • No nested / depth-5 include is issued for the fetch (asserted in test)
  • Related-list query access denied → returns []
  • relationshipOptions op available on context.serverAction, access-scoped through the same context
  • Changeset(s) added (core minor: serverAction op; ui minor: options module)

Blocked by

Metadata

Metadata

Assignees

No one assigned

    Labels

    ready-for-agentFully specified, ready for an AFK agent

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions