import type Koa from "koa"; import Router from "@koa/router"; import Emittery from "emittery"; import type { ActionName } from "../action.js"; import type { App } from "../app/app.js"; import type Context from "../context.js"; import type CalculatedField from "./calculated-field.js"; import CollectionItem from "./collection-item.js"; import { CollectionItemBody } from "./collection-item-body.js"; import type Field from "./field.js"; import type { FieldsetEncoded, FieldsetInput, FieldsetInputWithAllKeys, FieldsetOutput } from "./fieldset.js"; import ItemList, { type SortParams } from "./item-list.js"; import type Policy from "./policy.js"; import type SpecialFilter from "./special-filter.js"; import type { CollectionProperties } from "../schemas/generator.js"; export type CollectionEvent = "before:create" | "after:create" | "before:remove" | "after:remove" | "before:edit" | "after:edit"; export type CollectionCallback = ([context, item, event]: [ Context, CollectionItem, CollectionEvent ]) => Promise; export type CollectionValidationResult = { error: string; fields: string[]; }[]; export type CollectionOutput = FieldsetOutput; export type CollectionInput = FieldsetInput; export type CollectionInputWithAllKeys = FieldsetInputWithAllKeys; export type CollectionEncoded = FieldsetEncoded; export type Fieldnames = keyof T["fields"] & string; /** Creates a collection. All collections are automatically served via * the REST API, with permissions set by the Policies */ export default abstract class Collection { abstract fields: Record>; private emitter; /** the name of the collection, will be used as part of the URI in * the REST API */ name: string; /** policies for this collection. Who can do what */ policies: Partial<{ [a in ActionName]: Policy; }>; /** The policy to use when deciding on an action not specified in * `policies` */ defaultPolicy: Policy; /** The app this collection is tied to */ app: App; /** Whether or not should be visible in docs */ internal: boolean; named_filters: Record; calculated_fields: Record>; /** initializes the fields @internal */ initFieldDetails(): Promise; suCreate(data: CollectionInput): Promise>; /** the "unsafe" flavor of CRUD functions are meant for cases where you want to just get the errror message and parse it - for example, when you want to get a nice error that can be used to display errors in a form */ suCreateUnsafe(data: Record): Promise>; create(context: Context, data: CollectionInput): Promise>; /** extra safe = ensures that ALL fields are present, even if optional (if empty, specify 'undefined') as value. Useful for collection forms where you might add a collection field in the future and don't want to forget to handle it in the form, as well */ createExtraSafe(context: Context, data: CollectionInputWithAllKeys): Promise>; createUnsafe(context: Context, data: Record): Promise>; /** Makes a new item object that can be saved later */ make(input?: Partial>): CollectionItem; suGetByID(id: string): Promise>; getByID(context: Context, id: string, give_descriptive_errors?: boolean): Promise>; suRemoveByID(id: string, wait_for_after_events?: boolean): Promise; removeByID(context: Context, id: string, wait_for_after_events?: boolean): Promise; /** Get a policy for given action, an inherited policy, or the default * policy, if no policy is specified for this action */ getPolicy(action: ActionName): Policy; /** Initialize all the fields and filters * @internal */ init(app: App, collection_name: string): Promise; /** Whether or not any of the fields' behavior depends on the * current values of themselves or other fields * * @param action_name * the action for which to check @internal */ isOldValueSensitive(action_name: ActionName): boolean; /** Return a named filter from the collection * @param filter_name the name of the filter */ getNamedFilter(filter_name: string): SpecialFilter; suList(): ItemList; list(context: Context): ItemList; createFromDB(document: Record): CollectionItem; on(event_name: CollectionEvent, cb: CollectionCallback): Emittery.UnsubscribeFn; getRequiredFields(): Field[]; setPolicy(action: ActionName, policy: Policy): this; getRouter(): Router; clearListeners(): void; emit(event_name: string, event_data?: any): Promise; validate(context: Context, new_body: CollectionItemBody, old_body: CollectionItemBody, action: "create" | "edit"): Promise; static getFieldnames(collection: C): Array & string>; upsert>(this: C, context: Context, identify_by: IdentityField, entries: (CollectionInput & { [key in IdentityField]: CollectionInput[IdentityField]; })[]): Promise; hasFeed(): boolean; getFeedSize(_ctx: Koa.Context): Promise; getFeedSortOrder(_ctx: Koa.Context): Promise>; getFeedItems(ctx: Koa.Context): Promise[]>; mapFieldsToFeed(): FieldEntryMapping; getFeedTitle(ctx: Koa.Context): Promise; getFeedItemData(ctx: Koa.Context, item: CollectionItem): Promise; getFeed(ctx: Koa.Context): Promise; static getOpenApiSubfieldsSchema(context: Context, fields: Record>): Promise; getOpenApiSchema(context: Context): Promise; } export type FieldToFeedMappingEntry = T | ((context: Koa.Context, item: CollectionItem) => Promise); export type FeedEntryShape = { title: string; link: { rel?: string; type?: string; href: string; }[]; author: string[]; category?: string[]; id: string; content: string; published: Date; updated: Date; }; export type FieldEntryMapping = { [Property in keyof FeedEntryShape]: FieldToFeedMappingEntry; };