@webda/core
Version:
Expose API with Lambda
882 lines (881 loc) • 24.7 kB
TypeScript
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 };