Skip to content

tapedb/schema

Generated from the public tapedb/schema entry point’s TypeScript declarations. Signatures and comments are the API contract for this preview.

A predicate over the caller and the row. Throwing denies.

declare function check<F extends Fields = Fields>(test: (context: CheckContext<F>) => boolean): CheckDecision<F>;

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;

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): Schema<M>;
interface Access<F extends Fields = Fields> {
read?: RoleDecision | FilterDecision<F> | CheckDecision<F>;
create?: RoleDecision | CheckDecision<F>;
update?: RoleDecision | CheckDecision<F>;
delete?: RoleDecision | CheckDecision<F>;
}
interface AccessAuth {
/** The caller's subject, from your identity provider. */
sub: string;
role: WorkspaceRole;
workspaceId: string;
}
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[];
}
interface FieldFilter<T = Scalar> {
equals?: T;
not?: T | FieldFilter<T>;
in?: T[];
notIn?: T[];
gt?: T;
gte?: T;
lt?: T;
lte?: T;
}
interface Schema<M extends Models = Models> extends TapeDBSchema {
readonly models: M;
readonly graph: Record<string, ModelInfo>;
}
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>;
};
type DeleteBehaviour = "setNull" | "cascade" | "restrict";
type Include<M extends Models, F extends Fields> = {
[K in RelationKeys<F>]?: true | IncludeArgs<M, TargetFields<F[K], M>>;
};
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]>;
};

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";
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<WhereLeaf<TargetFieldsOf<F[K], M>>> : WhereLeaf<TargetFieldsOf<F[K], M>> | null;
} & {
AND?: Where<F, M> | Where<F, M>[];
OR?: Where<F, M>[];
NOT?: Where<F, M> | Where<F, M>[];
};
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>;
};