Skip to content

feat(search): let a search type name its label field - #729

Merged
ddeboer merged 3 commits into
mainfrom
feat/search-type-label-field
Aug 14, 2026
Merged

feat(search): let a search type name its label field#729
ddeboer merged 3 commits into
mainfrom
feat/search-type-label-field

Conversation

@ddeboer

@ddeboer ddeboer commented Aug 13, 2026

Copy link
Copy Markdown
Member

A type serving as a labelSource had to declare its display field with the
literal name label, so the word the API serves was decided by an internal role
rather than by the profile the schema declares to. In SCHEMA-AP-NDE, Person,
Organization, Place and DefinedTerm all carry schema:name, and consumers
expect name – but only a type nothing resolves labels from could serve it.

A type can now name its own label field:

export const term = defineSearchType({
  name: 'Term',
  class: `${SCHEMA}DefinedTerm`,
  labelField: 'name',
  fields: [{ name: 'name', kind: 'text', /* … */ }],
});

Changes

  • @lde/search: SearchTypeBase gains labelField; labelFieldOf resolves it
    through the new labelFieldNameOf (with DEFAULT_LABEL_FIELD), and the
    schema-wide validation message quotes the configured name. Both helpers are
    exported from the adapter surface.
  • @lde/search-api-graphql: a reference object type keys its resolved label off
    the label source’s configured name, so TermReference becomes { id, name }.
    ValueBucket.label is unchanged – it is per-facet-field, and a per-type name
    would make the bucket type non-uniform.
  • Since one emitted reference type cannot serve two words, buildGraphQLSchema
    now rejects fields that share a ref.typeName but resolve labels from sources
    disagreeing on their labelField – otherwise declaration order would silently
    decide which word both fields serve.
  • @lde/search-typesense needs no change: it already resolves the field through
    labelFieldOf. The engine-port property label also stays – it is a wire
    name, not a served one.
  • Docs: a ‘Naming the label field’ section in the search reference, plus updates
    to the GraphQL and Typesense references, packages/search/CONTEXT.md, and
    amendments to ADR 4 and ADR 8.

Non-breaking – every existing schema keeps the default.

Also fixes an unrelated test that this branch happens to make CI run: the
Prettier-peer case in print-sdl.test.ts mocked a module the earlier tests had
already loaded, so it passed locally and failed on CI. It now resets the module
graph and re-imports the module under test.

Fix #727

- add `SearchTypeBase.labelField`, defaulting to `label`, so the word a
  label source serves its display field under is the profile's, not one
  an internal role imposes
- resolve the label field through `labelFieldNameOf`; the validation
  message quotes the configured name
- key a GraphQL reference object's label off its label source's
  configured name, leaving `ValueBucket.label` per-facet-field
- document the option in the search reference, and amend ADR 4 and ADR 8
The earlier tests in the file load the real Prettier, so the mock only
took effect where the module graph happened to be re-evaluated – green
locally, red on CI. Reset and re-import the module under test instead.
…disagreeing label words

One emitted reference type cannot serve two words, and the memoisation
by `ref.typeName` would otherwise let declaration order decide which
field's label source wins. Also record why a label source is always a
Root Type, and drop a stale sentence the new docs section contradicted.
@ddeboer
ddeboer merged commit 88d3a88 into main Aug 14, 2026
4 checks passed
@ddeboer
ddeboer deleted the feat/search-type-label-field branch August 14, 2026 08:19
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.

Let a search type name its label field, instead of requiring 'label'

1 participant