tapedb/schema
Alles hier is stabiel tenzij het als experimenteel is gemarkeerd; zie API-stabiliteit.
Functions
Section titled “Functions”attachedTo
Section titled “attachedTo”A file rule: the file belongs to a row and follows its rules. locate
maps a path to the row’s id (null when the path names none, which denies).
Reading the file needs the row to be readable by the caller; writing or
deleting it needs the caller to be allowed to update the row.
files: { read: attachedTo(“task”, (path) => path.split(“/”)[1]) }
declare function attachedTo<K extends string>(model: K, locate: (path: string) => string | null | undefined): AttachedToDecision<K>;A predicate over the caller and the row. Throwing denies.
declare function check<F extends Fields = Fields>(test: (context: CheckContext<F>) => boolean): CheckDecision<F>;fileCheck
Section titled “fileCheck”A file rule: a predicate over the caller and the file. Throwing denies.
declare function fileCheck(test: (context: FileCheckContext) => boolean): FileCheckDecision;filter
Section titled “filter”read only: the rows the caller may see, as a filter compiled into SQL. An
array is OR of its filters.
declare function filter<F extends Fields = Fields>(build: (context: { auth: AccessAuth;}) => Where<F> | Where<F>[]): FilterDecision<F>;declare function model<F extends Fields>(fields: F, options?: ModelOptions): Model<F>;A minimum role, checked before any SQL.
declare function role(name: RoleName): RoleDecision;schema
Section titled “schema”Compiles models into the engine schema plus the client’s relation graph. Throws on anything the engine would only discover later: a relation to a model that does not exist, an ambiguous inverse, a reserved name.
declare function schema<M extends Models>(models: M, options?: SchemaOptions<Extract<keyof M, string>>): Schema<M>;Interfaces
Section titled “Interfaces”Access
Section titled “Access”interface Access<F extends Fields = Fields> { read?: RoleDecision | FilterDecision<F> | CheckDecision<F>; create?: RoleDecision | CheckDecision<F>; update?: RoleDecision | CheckDecision<F>; delete?: RoleDecision | CheckDecision<F>;}AccessAuth
Section titled “AccessAuth”interface AccessAuth { /** The caller's subject, from your identity provider. */ sub: string; role: WorkspaceRole; workspaceId: string;}CheckContext
Section titled “CheckContext”interface CheckContext<F extends Fields = Fields> { auth: AccessAuth; /** The stored row, for update, delete and read. */ row?: Partial<Row<F>> & { id: string; }; /** The incoming values, for create and update. */ data?: Record<string, unknown>; /** Field names this write sets. */ changed?: string[];}FieldFilter
Section titled “FieldFilter”interface FieldFilter<T = Scalar> { equals?: T; not?: T | FieldFilter<T>; in?: T[]; notIn?: T[]; gt?: T; gte?: T; lt?: T; lte?: T;}FileAccess
Section titled “FileAccess”Who may read, write and delete each file. Defaults: read member, write and delete editor.
interface FileAccess<K extends string = string> { read?: FileRuleDecision<K>; write?: FileRuleDecision<K>; delete?: FileRuleDecision<K>;}FileCheckContext
Section titled “FileCheckContext”interface FileCheckContext { auth: AccessAuth; /** For read and delete, the stored file; for write, the incoming one. */ file: FileInfo; /** For write, the stored file it would replace, if any. */ existing?: FileInfo;}FileInfo
Section titled “FileInfo”A file as file rules see it.
interface FileInfo { path: string; /** Bytes; null for a write whose size is not known yet (a multipart start). */ size: number | null; contentType: string | null; /** The uploader's claim subject. */ uploadedBy: string;}Schema
Section titled “Schema”interface Schema<M extends Models = Models> extends TapeDBSchema { readonly models: M; readonly graph: Record<string, ModelInfo>;}CreateData
Section titled “CreateData”type CreateData<F, M extends Models = Models> = { id?: string;} & RequiredParents<F> & { [K in RequiredScalarKeys<F>]: InputOf<F[K]>;} & { [K in OptionalScalarKeys<F>]?: InputOf<F[K]>;} & { [K in BelongsToKeys<F>]?: BelongsToInput<F[K], M>;} & { [K in BelongsToKeys<F> as `${K}Id`]?: string | null;} & { [K in HasManyKeys<F>]?: HasManyInput<F[K], M>;};DeleteBehaviour
Section titled “DeleteBehaviour”type DeleteBehaviour = "setNull" | "cascade" | "restrict";Include
Section titled “Include”type Include<M extends Models, F extends Fields> = { [K in RelationKeys<F>]?: true | IncludeArgs<M, TargetFields<F[K], M>>;};OrderBy
Section titled “OrderBy”type OrderBy<F> = Partial<Record<FilterKeys<F>, "asc" | "desc">> | Partial<Record<FilterKeys<F>, "asc" | "desc">>[];A stored row: its fields, the foreign keys of its belongsTo relations, and the system fields.
type Row<F> = { id: string; createdAt: number; updatedAt: number;} & { [K in ScalarKeys<F>]: OutputOf<F[K]>;} & { [K in BelongsToKeys<F> as `${K}Id`]: ForeignKeyOf<F[K]>;};ScalarKind
Section titled “ScalarKind”Field and relation builders: the t in model({ title: t.string() }).
Every builder is immutable: a modifier returns a new builder, so a shared
base field cannot be changed by one model’s .optional(). The type
parameters carry what the client needs to infer rows and inputs.
type ScalarKind = "string" | "number" | "boolean" | "date" | "json";UpdateData
Section titled “UpdateData”type UpdateData<F, M extends Models = Models> = { [K in ScalarKeys<F>]?: InputOf<F[K]>;} & { [K in BelongsToKeys<F>]?: BelongsToInput<F[K], M>;} & { [K in BelongsToKeys<F> as `${K}Id`]?: string | null;} & { [K in HasManyKeys<F>]?: HasManyInput<F[K], M>;};type Where<F extends Fields = Fields, M extends Models = Models> = Scalars<F> & { [K in RelationKeys<F>]?: F[K] extends HasMany ? ManyFilter<Where<TargetFieldsOf<F[K], M>, M>> : Where<TargetFieldsOf<F[K], M>, M> | null;} & { AND?: Where<F, M> | Where<F, M>[]; OR?: Where<F, M>[]; NOT?: Where<F, M> | Where<F, M>[];};Constants
Section titled “Constants”declare const t: { string: () => Field<"string", false, false>; number: () => Field<"number", false, false>; boolean: () => Field<"boolean", false, false>; /** Stored as epoch milliseconds; accepts a `Date`, milliseconds or an ISO string. */ date: () => Field<"date", false, false>; /** Any JSON value. Not filterable or sortable. */ json: () => Field<"json", false, false>; belongsTo: <T extends string>(target: T, options?: BelongsToOptions) => BelongsTo<T, false>; hasMany: <T extends string>(target: T, options?: HasManyOptions) => HasMany<T>;};