import type { AxiosResponse, AxiosResponseHeaders, RawAxiosResponseHeaders, } from 'axios'; import type { ModelConfig } from '../typings'; import type { DatastoreConfig } from './Datastore'; import type Datastore from './Datastore'; export type { AxiosResponse, DatastoreConfig }; import { omit } from 'lodash'; export default class Model { modelConfig: ModelConfig; datastore: Datastore; constructor(datastore: Datastore, modelConfig: ModelConfig) { this.modelConfig = modelConfig; this.datastore = datastore; } get name() { return this.modelConfig.name; } async request(handler: Function, ...args: any[]): Promise { const { data } = await handler.call(this.datastore, ...args); return data; } heartbeat(): Promise<{ status: string }> { return this.request(this.datastore.heartbeat); } createModel(): Promise { return this.request(this.datastore.createModel, this.modelConfig); } updateModel(): Promise { return this.request(this.datastore.updateModel, this.modelConfig); } createModelIndexes(): Promise { return this.request(this.datastore.createModelIndexes, this.modelConfig); } getSchema(): Promise { return this.request(this.datastore.getSchema, this.name); } async encryptOne(payload: Partial, fields: string[] = []): Promise { const [decrypted] = await this.request( this.datastore.encrypt, this.name, [payload], fields, ); return decrypted; } encryptMany(payloads: Partial[], fields: string[] = []): Promise { return this.request(this.datastore.encrypt, this.name, payloads, fields); } async decryptOne(payload: Partial, fields: string[] = []): Promise { const [decrypted] = await this.request( this.datastore.decrypt, this.name, [payload], fields, ); return decrypted; } decryptMany(payloads: Partial[], fields: string[] = []): Promise { return this.request(this.datastore.decrypt, this.name, payloads, fields); } createOne(payload: Partial, headers?: object): Promise { return this.request(this.datastore.create, this.name, payload, headers); } createMany(payloads: Partial[]): Promise { return Promise.all(payloads.map((p) => this.createOne(p))); } /** * @deprecated in favor of createOne + createMany */ create(payload: T | T[]): Promise { if (Array.isArray(payload)) { return Promise.all( payload.map((p) => this.request(this.datastore.create, this.name, p)), ) as Promise; } return this.request( this.datastore.create, this.name, payload, ) as Promise; } updateOne(payload: Partial, headers?: object): Promise { return this.request( this.datastore.update, this.name, /* @ts-ignore */ payload[this.modelConfig.correlation_field], omit(payload, this.modelConfig.correlation_field), headers, ); } updateMany(payloads: Partial[]): Promise { return Promise.all(payloads.map((p) => this.updateOne(p))); } /** * @deprecated */ update(payload: object | object[]): Promise { if (Array.isArray(payload)) { return Promise.all( payload.map((p) => this.request( this.datastore.update, this.name, p[this.modelConfig.correlation_field], omit(p, this.modelConfig.correlation_field), ), ), ) as Promise; } return this.request( this.datastore.update, this.name, /* @ts-ignore */ payload[this.modelConfig.correlation_field], omit(payload, this.modelConfig.correlation_field), ) as Promise; } apply( eventType: string, payload: object, headers?: object, eventVersion = '0_0_0', ): Promise { return this.request( this.datastore.apply, this.name, /* @ts-ignore */ payload[this.modelConfig.correlation_field], eventType, eventVersion, omit(payload, this.modelConfig.correlation_field), headers, ); } get( correlationId: string, headers?: { 'force-primary'?: true; }, ): Promise { return this.request(this.datastore.get, this.name, correlationId, headers); } count(query: T & Record): Promise { return this.datastore.count.call(this.datastore, this.name, query); } find( query: Partial, page?: number, pageSize?: number, headers?: { page?: number; 'page-size'?: number; 'cursor-last-id'?: string; 'force-primary'?: true; }, ): Promise { return this.request( this.datastore.find, this.name, query, page, pageSize, headers, ); } events( correlationId: string, page?: number, pageSize?: number, ): Promise { return this.request( this.datastore.events, this.name, correlationId, page, pageSize, ); } version(correlationId: string, version: number): Promise { return this.request( this.datastore.version, this.name, correlationId, version, ); } at(correlationId: string, date: Date | string): Promise { return this.request(this.datastore.at, this.name, correlationId, date); } restore(correlationId: string, version: number): Promise { return this.request( this.datastore.restore, this.name, correlationId, version, ); } snapshot(correlationId: string): Promise { return this.request(this.datastore.snapshot, this.name, correlationId); } archive(correlationId: string, deep?: boolean): Promise { return this.request(this.datastore.archive, this.name, correlationId, deep); } unarchive(correlationId: string, deep?: boolean): Promise { return this.request( this.datastore.unarchive, this.name, correlationId, deep, ); } delete(correlationId: string, deep?: boolean): Promise { return this.request(this.datastore.delete, this.name, correlationId, deep); } async updateOverwhelmingly( query: object, handler: (entity: T) => Promise, progress: ( stats: { total: number; done: number; error: number; progress: number; restored: number; }, entity: T, headers: RawAxiosResponseHeaders | AxiosResponseHeaders, ) => void, pageSize?: number, ) { return this.datastore.updateOverwhelmingly( this.name, query, handler, progress, pageSize, ); } }