UNPKG

@webda/core

Version:

Expose API with Lambda

882 lines (881 loc) 24.7 kB
import { EventEmitter } from "events"; import { JSONSchema7 } from "json-schema"; import { ModelGraph, ModelsTree } from "../application.js"; import { Core } from "../core.js"; import { Service } from "../services/service.js"; import { Store, StoreEvents } from "../stores/store.js"; import { OperationContext } from "../utils/context.js"; import { HttpMethodType } from "../utils/httpcontext.js"; import { ModelActions, RawModel } from "./relations.js"; /** * Expose the model through API or GraphQL if it exists * The model will be exposed using its class name + 's' * If you need to have a specific plural, use the annotation WebdaPlural * to define the plural name * * @returns */ export declare function Expose(params?: Partial<ExposeParameters>): (target: CoreModelDefinition) => void; /** * */ export declare class CoreModelQuery { private type; private model; private attribute; private targetModel; constructor(type: string, model: CoreModel, attribute: string); /** * Retrieve target model definition * @returns */ getTargetModel(): CoreModelDefinition; /** * Query the object * @param query * @returns */ query(query?: string, context?: OperationContext): Promise<{ results: CoreModel[]; continuationToken?: string; }>; /** * Complete the query with condition * @param query * @returns */ protected completeQuery(query?: string): string; /** * * @param callback * @param context */ forEach(callback: (model: any) => Promise<void>, query?: string, context?: OperationContext, parallelism?: number): Promise<void>; /** * Iterate through all * @param context * @returns */ iterate(query?: string, context?: OperationContext): AsyncGenerator<CoreModel, any, any>; /** * Get all the objects * @returns */ getAll(context?: OperationContext): Promise<this[]>; } /** * Attribute of an object * * Filter out methods */ export type Attributes<T extends object> = { [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]; /** * Filter type keys by type */ export type FilterAttributes<T extends CoreModel, K> = { [L in keyof T]: T[L] extends K ? L : never; }[keyof T]; /** * Define an Action on a model * * It is basically a method designed to be called by the API or external * systems */ export interface ModelAction { /** * Method for the route * * By default ["PUT"] */ methods?: HttpMethodType[]; /** * Define if the action is global or per object * * The method that implement the action must be called * `_${actionName}` */ global?: boolean; /** * Additional openapi info */ openapi?: any; /** * Method of the action */ method?: string; } /** * Expose parameters for the model */ export interface ExposeParameters { /** * If model have parent but you still want it to be exposed as root * in domain-like service: DomainService, GraphQL * * It would create alias for the model in the root too */ root?: boolean; /** * You can select to not expose some methods like create, update, delete, get, query */ restrict: { /** * Create a new object */ create?: boolean; /** * Update an existing object * * Includes PUT and PATCH */ update?: boolean; /** * Query the object */ query?: boolean; /** * Get a single object */ get?: boolean; /** * Delete an object */ delete?: boolean; /** * Do not create operations for the model */ operation?: boolean; }; } /** * */ export interface CoreModelDefinition<T extends CoreModel = CoreModel> extends EventEmitter { new (): T; /** * If the model have some Expose annotation */ Expose?: ExposeParameters; /** * Create a CoreModel object loaded with the content of object * * It allows polymorphism from Store * * @param model to create by default * @param object to load data from * @param context if the data is unsafe from http */ factory<T extends CoreModel>(this: Constructor<T>, object: Partial<T>, context?: OperationContext): T; /** * Get the model actions */ getActions(): { [key: string]: ModelAction; }; /** * Get the model store */ store(): Store<T>; /** * Get the model schema */ getSchema(): JSONSchema7; /** * Get the model hierarchy */ getHierarchy(): { ancestors: string[]; children: ModelsTree; }; /** * Get the model relations */ getRelations(): ModelGraph; /** * Get Model identifier */ getIdentifier(short?: boolean): string; /** * Complete uuid useful to implement uuid prefix or suffix * @param uid */ completeUid(uid: string): string; /** * Get the model uuid field if you do not want to use the uuid field */ getUuidField(): string; /** * Permission query for the model * @param context */ getPermissionQuery(context?: OperationContext): null | { partial: boolean; query: string; }; /** * Reference to an object without doing a DB request yet */ ref: typeof CoreModel.ref; /** * Create a new model * @param this * @param data */ create<T extends CoreModel>(this: Constructor<T>, data: RawModel<T>): Promise<T>; /** * Query the model * @param query */ query(query?: string, includeSubclass?: boolean, context?: OperationContext): Promise<{ results: T[]; continuationToken?: string; }>; /** * Iterate through objects * @param query * @param includeSubclass * @param context */ iterate(query?: string, includeSubclass?: boolean, context?: OperationContext): AsyncGenerator<T>; /** * Listen to events on the model * @param event * @param listener * @param async */ on<T extends CoreModel, Key extends keyof StoreEvents>(this: Constructor<T>, event: Key, listener: (evt: StoreEvents[Key]) => any, async?: boolean): this; /** * Listen to events on the model asynchronously * @param event * @param listener */ onAsync<T extends CoreModel, Key extends keyof StoreEvents>(this: Constructor<T>, event: Key, listener: (evt: StoreEvents[Key]) => any): this; /** * Emit an event for this class * @param this * @param event * @param evt */ emit<T extends CoreModel, Key extends keyof StoreEvents>(this: Constructor<T>, event: Key, evt: StoreEvents[Key]): any; /** * Emit an event for this class and wait for all listeners to finish * @param this * @param event * @param evt */ emitSync<T extends CoreModel, Key extends keyof StoreEvents>(this: Constructor<T>, event: Key, evt: StoreEvents[Key]): Promise<void>; /** * Return the event on the model that can be listened to by an * external authorized source * @see authorizeClientEvent */ getClientEvents(): ({ name: string; global?: boolean; } | string)[]; /** * Authorize a public event subscription * @param event * @param context */ authorizeClientEvent(_event: string, _context: OperationContext, _model?: T): boolean; /** * EventEmitter interface * @param event * @param listener */ addListener(event: string | symbol, listener: (...args: any[]) => void): this; /** * EventEmitter interface * @param event * @param listener */ once(event: string | symbol, listener: (...args: any[]) => void): this; /** * EventEmitter interface * @param event * @param listener */ removeListener(event: string | symbol, listener: (...args: any[]) => void): this; /** * EventEmitter interface * @param event * @param listener */ off(eventName: string | symbol, listener: (...args: any[]) => void): this; /** * EventEmitter interface * @param event * @param listener */ removeAllListeners(eventName?: any): this; } export type Constructor<T, K extends Array<any> = []> = new (...args: K) => T; /** * Make a property hidden from json and schema * * This property will not be saved in the store * Nor it will be exposed in the API * * @param target * @param propertyKey */ export declare function NotEnumerable(target: any, propertyKey: string): void; /** * Define an object method as an action * @param target * @param propertyKey */ export declare function Action(options?: { methods?: HttpMethodType[]; openapi?: any; name?: string; }): (target: any, propertyKey: string) => void; export declare class ModelRef<T extends CoreModel> { protected uuid: string; protected store: Store<T>; protected model: CoreModelDefinition<T>; protected parent: CoreModel; constructor(uuid: string, model: CoreModelDefinition<T>, parent?: CoreModel); get(context?: OperationContext): Promise<T>; set(id: string | T): void; toString(): string; toJSON(): string; getUuid(): string; deleteItemFromCollection(prop: FilterAttributes<T, any[]>, index: number, itemWriteCondition: any, itemWriteConditionField?: string): Promise<this>; upsertItemToCollection(prop: FilterAttributes<T, any[]>, item: any, index?: number, itemWriteCondition?: any, itemWriteConditionField?: string): Promise<this>; exists(): Promise<boolean>; delete(): Promise<void>; conditionalPatch(updates: Partial<T>, conditionField: any, condition: any): Promise<boolean>; patch(updates: Partial<T>): Promise<boolean>; setAttribute(attribute: keyof T, value: any): Promise<this>; removeAttribute(attribute: keyof T, itemWriteCondition?: any, itemWriteConditionField?: keyof T): Promise<this>; incrementAttributes(info: { property: FilterAttributes<T, number>; value: number; }[]): Promise<this>; } export declare class ModelRefWithCreate<T extends CoreModel> extends ModelRef<T> { /** * Allow to create a model * @param defaultValue * @param context * @param withSave * @returns */ create(defaultValue: RawModel<T>, context?: OperationContext, withSave?: boolean): Promise<T>; /** * Load a model from the known store * * @param this the class from which the static is called * @param id of the object to load * @param defaultValue if object not found return a default object * @param context to set on the object * @returns */ getOrCreate(defaultValue: RawModel<T>, context?: OperationContext, withSave?: boolean): Promise<T>; } export declare class ModelRefCustom<T extends CoreModel> extends ModelRef<T> { uuid: string; constructor(uuid: string, model: CoreModelDefinition<T>, data: any, parent: CoreModel); toJSON(): any; getUuid(): string; } export type ModelRefCustomProperties<T extends CoreModel, K> = ModelRefCustom<T> & K; export declare const Emitters: WeakMap<Constructor<CoreModel>, EventEmitter>; /** * Basic Object in Webda * * It is used to define a data stored * Any variable starting with _ can only be set by the server * Any variable starting with __ won't be exported outside of the server * * @class * @WebdaModel */ declare class CoreModel { /** * Class reference to the object */ __class: CoreModelDefinition<this>; /** * Type name */ __type: string; /** * Types name */ __types: string[]; /** * Object context * * @TJS-ignore */ __ctx: OperationContext; /** * If object is attached to its store * * @TJS-ignore */ __store: Store<this>; __dirty: Set<string | symbol>; /** * Creation date */ _creationDate: Date; /** * Last update date */ _lastUpdate: Date; /** * If an object is deleted but not removed from DB for historic * * @ignore */ __deleted: boolean; constructor(); /** * Listen to events on the model * @param event * @param listener * @param async */ static on<T extends CoreModel, Key extends keyof StoreEvents>(this: Constructor<T>, event: Key, listener: (evt: StoreEvents[Key]) => any, async?: boolean): any; /** * Emit an event for this class * @param this * @param event * @param evt */ static emit<T extends CoreModel, Key extends keyof StoreEvents>(this: Constructor<T>, event: Key, evt: StoreEvents[Key]): void; /** * Emit an event for this class and wait for all listeners to finish * @param this * @param event * @param evt */ static emitSync<T extends CoreModel, Key extends keyof StoreEvents>(this: Constructor<T>, event: Key, evt: StoreEvents[Key]): Promise<void>; /** * Listen to events on the model asynchronously * @param event * @param listener */ static onAsync<Key extends keyof StoreEvents>(event: Key, listener: (evt: StoreEvents[Key]) => any, queue?: string): any; /** * * @param event * @param listener * @returns */ static addListener<Key extends keyof StoreEvents>(event: Key, listener: (...args: any[]) => void): any; static emitter(method: any, ...args: any[]): any; static removeListener(...args: any[]): any; static off(...args: any[]): any; static once(...args: any[]): any; static removeAllListeners(...args: any[]): any; static setMaxListeners(...args: any[]): any; static getMaxListeners(...args: any[]): any; static listeners(...args: any[]): any; static rawListeners(...args: any[]): any; static listenerCount(...args: any[]): any; static prependListener(...args: any[]): any; static prependOnceListener(...args: any[]): any; static eventNames(...args: any[]): any; /** * * @returns */ static getRelations(): ModelGraph; /** * Do not declare any public events by default * @returns */ static getClientEvents(): any[]; /** * Does not allow any event by default * @param _event * @param _context * @returns */ static authorizeClientEvent(_event: string, _context: OperationContext, _model?: CoreModel): boolean; /** * Get Store for this model * @param this * @returns */ static store<T extends CoreModel>(this: Constructor<T>): Store<T>; /** * Complete the uid with prefix if any * * Useful when object are stored with a prefix for full uuid * @param uid * @returns */ static completeUid(uid: string): string; /** * Return the known schema * @returns */ static getSchema(): JSONSchema7; /** * Get a reference to a model * @param this * @param uid * @returns */ static ref<T extends CoreModel>(this: Constructor<T>, uid: string): ModelRefWithCreate<T>; /** * Get a reference to a model * @param this * @param uid * @returns */ static create<T extends CoreModel>(this: Constructor<T>, data: RawModel<T>): Promise<T>; /** * Get identifier for this model * @returns */ static getIdentifier(short?: boolean): string; /** * Get the model hierarchy * * Ancestors will contain every model it inherits from * Children will contain every model that inherits from this model in a tree structure */ static getHierarchy(): { ancestors: string[]; children: ModelsTree; }; /** * Unflat an object * @param data * @param split * @returns */ static unflat<T = any>(data: any, split?: string): T; /** * Create subobject for a model * * Useful for counters * * @param split * @returns */ unflat<T>(split?: string): T; /** * Flat an object into another * * { * a: { * b: 1 * }, * c: 1 * } * * become * * { * "a#b": 1 * "c": 1 * } * * @param target * @param data * @param split * @param prefix */ static flat(target: any, data: any, split?: string, prefix?: string): any; /** * Complete the query with __type/__types * @param query * @param includeSubclass * @returns */ protected static completeQuery(query: string, includeSubclass?: boolean): string; /** * Iterate through the model * * How to use a iterator is: * * ``` * for await (const model of CoreModel.iterate()) { * // Do something with my model * } * ``` * * @param this * @param query * @param includeSubclass * @param context * @returns */ static iterate<T extends CoreModel>(this: Constructor<T>, query?: string, includeSubclass?: boolean, context?: OperationContext): AsyncGenerator<T>; /** * Query for models * @param this * @param id * @returns */ static query<T extends CoreModel>(this: Constructor<T>, query?: string, includeSubclass?: boolean, context?: OperationContext): Promise<{ results: T[]; continuationToken?: string; }>; /** * Return a proxy to the object to detect if dirty * @returns */ getProxy(): this; /** * Return true if needs a save * @returns */ isDirty(): boolean; /** * * @returns the uuid of the object */ getUuid(): string; /** * * @param uuid * @param target */ setUuid(uuid: string, target?: this): this; /** * Get actions callable on an object * * This will expose them by the Store with /storeUrl/{uuid}/{action} */ static getActions<T>(this: Constructor<T>): ModelActions; /** * Return the expressable query for permission * * @param context of the query * @returns */ static getPermissionQuery(_ctx: OperationContext): null | { partial: boolean; query: string; }; checkAct(context: OperationContext, action: "create" | "update" | "get" | "delete" | "get_binary" | "detach_binary" | "attach_binary" | "update_binary_metadata" | "subscribe" | string): Promise<void>; /** * By default nothing is permitted on a CoreModel * @returns */ canAct(_context: OperationContext, _action: "create" | "update" | "get" | "delete" | "get_binary" | "detach_binary" | "attach_binary" | "update_binary_metadata" | "subscribe" | string): Promise<string | boolean>; /** * Get the UUID property */ static getUuidField(): string; /** * Create an object * @returns */ static factory<T extends CoreModel>(this: Constructor<T>, object: Partial<T>, context?: OperationContext): T; /** * Detect what looks like a CoreModel but can be from different version * @param object * @returns */ static instanceOf(object: any): boolean; /** * Return a unique reference within the application to the object * * It contains the Store containing it * @returns */ getFullUuid(): string; /** * Get an object from the full uuid * @param core * @param fullUuid * @param partials * @returns */ static fromFullUuid<T extends CoreModel = CoreModel>(fullUuid: string, core?: Core, partials?: any): Promise<T>; /** * Allow to define custom permission per attribute * * This method allows you to do permission based attribute * But also a mask destructive attribute * * @param key * @param value * @param mode * @param context * @returns updated value */ attributePermission(key: string, value: any, mode: "READ" | "WRITE", context?: OperationContext): any; /** * Load an object from RAW * * @param raw data * @param secure if false will ignore any _ variable */ load(raw: RawModel<this>, secure?: boolean, relations?: boolean): this; /** * Patch every attribute that is based on a relation * to add all the helpers */ protected handleRelations(): void; /** * Context of the request */ setContext(ctx: OperationContext): this; /** * Get object context * * Global object does not belong to a request */ getContext<T extends OperationContext>(): T; /** * Return the object registered store */ getStore(): Store<this>; /** * Get the object * @returns */ get(): Promise<this>; /** * Get the object again * * @throws Error if the object is not coming from a store */ refresh(): Promise<this>; /** * Delete this object * * @throws Error if the object is not coming from a store */ delete(): Promise<void>; /** * Patch current object with this update * @param obj * @param conditionField if null no condition used otherwise fallback to lastUpdate * @param conditionValue */ patch(obj: Partial<this>, conditionField?: keyof this | null, conditionValue?: any): Promise<void>; /** * Save this object * * @throws Error if the object is not coming from a store */ save(full?: boolean | keyof this, ...args: (keyof this)[]): Promise<this>; /** * Validate objet modification * * @param ctx * @param updates */ validate(ctx: OperationContext, updates: any, ignoreRequired?: boolean): Promise<boolean>; /** * Generate uuid for the object * * @param object * @returns */ generateUid(_object?: any): string; /** * Return the object to be serialized without the __store * * @param stringify * @returns */ toStoredJSON(stringify?: boolean): any | string; /** * Get a pre typed service * * @param service to retrieve * WARNING: Only object attached to a store can retrieve service */ getService<T extends Service>(service: any): T; /** * Remove the specific attributes if not secure * * * * @param secure serialize server fields also * @returns filtered object to be serialized */ _toJSON(secure: any): any; /** * Return the object without sensitive attributes * * @returns Object to serialize */ toJSON(): any; /** * Called when object is about to be deleted */ _onDelete(): Promise<void>; /** * Called when object has been deleted */ _onDeleted(): Promise<void>; /** * Called when object is retrieved */ _onGet(): Promise<void>; /** * Called when object is about to be saved */ _onSave(): Promise<void>; /** * Called when object is saved */ _onSaved(): Promise<void>; /** * Called when object is about to be updates * * @param updates to be send */ _onUpdate(_updates: any): Promise<void>; /** * Called when object is updated */ _onUpdated(): Promise<void>; /** * Set attribute on the object and database * @param property * @param value */ setAttribute(property: keyof this, value: any): Promise<void>; /** * Remove attribute from both the object and db * @param property */ removeAttribute(property: keyof this): Promise<void>; /** * Increment an attribute both in store and object * @param property * @param value */ incrementAttribute(property: FilterAttributes<this, number>, value: number): Promise<void>; /** * Return a model ref * @returns */ getRef<T extends this>(): ModelRef<T>; /** * Increment a attributes both in store and object * @param info */ incrementAttributes(info: { property: string; value: number; }[]): Promise<void>; } /** * CoreModel with a uuid */ declare class UuidModel extends CoreModel { uuid: string; /** * @override */ validate(ctx: OperationContext<any, any>, updates: any, ignoreRequired?: boolean): Promise<boolean>; } export { CoreModel, UuidModel };