Entity / foldkit-entity
Selecting a view
A Selection names the members a consumer wants and carries the schema of the
value that results. It does not fetch that value; whoever produces it (a server
adapter, a test, a form) decodes against selection.schema.
const AuthorOption = Entity.select(Blog.Author, { id: true, name: true })
const PostRow = Entity.select(Blog.Post, {
title: true,
commentCount: true,
author: AuthorOption,
editor: AuthorOption,
comments: true,
})
type PostRow = Selected<typeof PostRow>
// {
// title: string
// commentCount: number
// author: { id: string; name: string }
// editor: { id: string; name: string } | null
// comments: ReadonlyArray<{ entity: 'Comment'; id: string }>
// }| Member | Select with | Yields |
|---|---|---|
| Field, Derived | true | the member's own schema, checks included |
| Relation | true | an EntityRef: { entity, id } |
| Relation | a Selection of its target | that Selection's value |
many Relation | Entity.page(selection, window) | a page of that Selection's values: { items, hasNext, hasPrevious } |
A many relation yields an array, and an optional one is nullable. A
Selection is an ordinary value, so AuthorOption above is declared once and
reused. Nesting is always explicit, which is what keeps a cycle finite.
A page of a relation
A post may have ten thousand comments. Entity.page reads a many relation a
page at a time:
const CommentBody = Entity.select(Blog.Comment, { body: true })
const PostWithComments = Entity.select(Blog.Post, {
title: true,
comments: Entity.page(CommentBody, { first: 10 }),
})
// { title: string, comments: { items: { body: string }[], hasNext: boolean, hasPrevious: boolean } }The window is first or last, with after or before a cursor. A page is a
view's shape, as neutral as "many means an array", so it is declared here.
What a cursor is and how the rows are ordered belong to whoever fetches: the
cursor is an opaque string an earlier answer handed out. Reading on is another
Selection with another window.
An unknown member, a nested Selection on a field, a page of a one relation,
and a Selection of the wrong
Entity are type errors, and Entity.select throws for untyped callers.